Cool-Y.github.io/2019/07/25/Debug-a-router-firmware/index.html
2021-05-21 15:35:38 +08:00

1199 lines
56 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html class="theme-next muse use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">
<script src="/lib/pace/pace.min.js?v=1.0.2"></script>
<link href="/lib/pace/pace-theme-center-atom.min.css?v=1.0.2" rel="stylesheet">
<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">
<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">
<link rel="apple-touch-icon" sizes="180x180" href="/images/hackerrank.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="32x32" href="/images/hackerrank.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="16x16" href="/images/hackerrank.png?v=5.1.4">
<link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">
<meta name="keywords" content="小米,路由器,调试,">
<link rel="alternate" href="/atom.xml" title="混元霹雳手" type="application/atom+xml">
<meta name="description" content="如果能够调试一个IoT设备那挖漏洞将会简单很多">
<meta name="keywords" content="小米,路由器,调试">
<meta property="og:type" content="article">
<meta property="og:title" content="远程调试小米路由器固件">
<meta property="og:url" content="https://cool-y.github.io/2019/07/25/Debug-a-router-firmware/index.html">
<meta property="og:site_name" content="混元霹雳手">
<meta property="og:description" content="如果能够调试一个IoT设备那挖漏洞将会简单很多">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2021-04-10T13:39:05.082Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="远程调试小米路由器固件">
<meta name="twitter:description" content="如果能够调试一个IoT设备那挖漏洞将会简单很多">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Muse',
version: '5.1.4',
sidebar: {"position":"left","display":"always","offset":12,"b2t":false,"scrollpercent":true,"onmobile":true},
fancybox: true,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="https://cool-y.github.io/2019/07/25/Debug-a-router-firmware/">
<title>远程调试小米路由器固件 | 混元霹雳手</title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container sidebar-position-left page-post-detail">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">混元霹雳手</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">Battle⚔ 2 the world🌎</p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br>
首页
</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br>
关于
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br>
标签
</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories/" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br>
分类
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
归档
</a>
</li>
<li class="menu-item menu-item-bookmarks">
<a href="/bookmarks/" rel="section">
<i class="menu-item-icon fa fa-fw fa-map"></i> <br>
书签
</a>
</li>
<li class="menu-item menu-item-album">
<a href="/album/" rel="section">
<i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br>
相簿
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<div id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://cool-y.github.io/2019/07/25/Debug-a-router-firmware/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Cool-Y">
<meta itemprop="description" content>
<meta itemprop="image" content="/images/avatar.png">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="混元霹雳手">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">远程调试小米路由器固件</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2019-07-25T22:17:08+08:00">
2019-07-25
</time>
</span>
<span class="post-category">
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/IOT/" itemprop="url" rel="index">
<span itemprop="name">IOT</span>
</a>
</span>
</span>
<span id="/2019/07/25/Debug-a-router-firmware/" class="leancloud_visitors" data-flag-title="远程调试小米路由器固件">
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数&#58;</span>
<span class="leancloud-visitors-count"></span>
</span>
<div class="post-wordcount">
<span class="post-meta-item-icon">
<i class="fa fa-file-word-o"></i>
</span>
<span title="字数统计">
3k 字
</span>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-clock-o"></i>
</span>
<span title="阅读时长">
13 分钟
</span>
</div>
<div class="post-description">
如果能够调试一个IoT设备那挖漏洞将会简单很多
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="0x00-背景与简介"><a href="#0x00-背景与简介" class="headerlink" title="0x00 背景与简介"></a>0x00 背景与简介</h1><p>在分析嵌入式设备的固件时只采用静态分析方式通常是不够的你需要实际执行你的分析目标来观察它的行为。在嵌入式Linux设备的世界里很容易把一个调试器放在目标硬件上进行调试。如果你能在自己的系统上运行二进制文件而不是拖着硬件做分析, 将会方便很多这就需要用QEMU进行仿真。<br>虽然QEMU在模拟核心芯片组包括CPU上都做的很不错但是QEMU往往不能提供你想运行的二进制程序需要的硬件。最常见问题是在运行系统服务如Web服务器或UPnP守护进程时缺乏NVRAM。解决方法是使用nvram-faker库拦截由libnvram.so提供的nvram_get()调用。即使解决了NVRAM问题该程序还可能会假设某些硬件是存在的如果硬件不存在该程序可能无法运行或者即便它运行了行为可能也与在其目标硬件上运行时有所不同。针对这种情况下我认为有三种解决方法</p>
<ol>
<li>修补二进制文件。这取决于期望什么硬件,以及它不存在时的行为是什么。</li>
<li>把复杂的依赖于硬件的系统服务拆分成小的二级制文件。如跳过运行Web服务器仅仅从shell脚本运行cgi二进制文件。因为大多数cgi二进制文件将来自Web服务器的输入作为标准输入和环境变量的组合并通过标准输出将响应发送到Web服务器。</li>
<li>拿到设备的shell直接在真机上进行调试这是最接近真实状况的方法。</li>
</ol>
<hr>
<h1 id="REF"><a href="#REF" class="headerlink" title="REF"></a>REF</h1><p><strong>综合:</strong><br><a href="https://shadow-file.blogspot.com/2015/01/dynamically-analyzing-wifi-routers-upnp.html" target="_blank" rel="noopener">国外大神的博客</a><br><a href="https://wooyun.js.org/drops/%E9%80%9A%E8%BF%87QEMU%20%E5%92%8C%20IDA%20Pro%E8%BF%9C%E7%A8%8B%E8%B0%83%E8%AF%95%E8%AE%BE%E5%A4%87%E5%9B%BA%E4%BB%B6.html" target="_blank" rel="noopener">通过QEMU和IDAPro远程调试设备固件</a><br><a href="https://ray-cp.github.io/archivers/MIPS_Debug_Environment_and_Stack_Overflow" target="_blank" rel="noopener">MIPS漏洞调试环境安装及栈溢出</a><br><a href="https://wiki.x10sec.org/pwn/arm/environment/" target="_blank" rel="noopener">环境搭建onCTFWIKI</a><br><a href="https://www.anquanke.com/post/id/171918" target="_blank" rel="noopener">路由器漏洞训练平台</a><br><a href="https://www.anquanke.com/post/id/180714" target="_blank" rel="noopener">路由器0day漏洞挖掘实战</a><br><a href="https://5alt.me/wiki/%E9%80%86%E5%90%91" target="_blank" rel="noopener">逆向常用工具</a></p>
<p><strong>环境搭建:</strong><br><a href="https://xz.aliyun.com/t/3826" target="_blank" rel="noopener">路由器漏洞挖掘测试环境的搭建之问题总结</a></p>
<p><strong>Linux相关知识</strong><br><a href="http://xstarcd.github.io/wiki/Cloud/qcow2_raw_vmdk.html" target="_blank" rel="noopener">qcow2、raw、vmdk等镜像格式</a><br><a href="http://joe.is-programmer.com/posts/17753.html" target="_blank" rel="noopener">Linux 引导过程内幕</a><br><a href="https://zhuanlan.zhihu.com/p/32051645" target="_blank" rel="noopener">Linux启动过程</a></p>
<p><strong>调试案例</strong><br><a href="https://xz.aliyun.com/t/5681" target="_blank" rel="noopener">CVE-2019-10999复现</a><br><a href="https://ray-cp.github.io/archivers/router_vuln_book_note" target="_blank" rel="noopener">《家用路由器0day漏洞挖掘》部分案例</a><br><a href="https://paper.seebug.org/448/" target="_blank" rel="noopener">TP-LINK WR941N路由器研究</a></p>
<hr>
<h1 id="0x01-基础条件"><a href="#0x01-基础条件" class="headerlink" title="0x01 基础条件"></a>0x01 基础条件</h1><ul>
<li><p>一系列的工具,包括:<br><strong>binwalk</strong> 帮助你解包固件<br><strong>buildroot</strong> mips交叉编译环境帮助你在x86平台下编译mips架构的目标程序 <a href="https://xz.aliyun.com/t/2505#toc-6" target="_blank" rel="noopener">https://xz.aliyun.com/t/2505#toc-6</a><br><strong>qemu</strong> 帮助你模拟mips环境<br><strong>MIPS gdbinit</strong> 文件使得使用gdb调试mips程序时更方便 <a href="https://github.com/zcutlip/gdbinit-mips" target="_blank" rel="noopener">https://github.com/zcutlip/gdbinit-mips</a><br><strong>miranda工具</strong> 用于UPnP分析 <a href="https://code.google.com/p/miranda-upnp/" target="_blank" rel="noopener">https://code.google.com/p/miranda-upnp/</a><br><strong>MIPS静态汇编审计</strong> 辅助脚本 <a href="https://github.com/giantbranch/mipsAudit" target="_blank" rel="noopener">https://github.com/giantbranch/mipsAudit</a><br><strong>静态编译的gdbserver</strong> <a href="https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver" target="_blank" rel="noopener">https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver</a></p>
</li>
<li><p>一个<strong>mips Linux</strong>环境:<br>在qemu系统模式下需要模拟整个计算机系统</p>
</li>
</ul>
<hr>
<h1 id="0x02-qemu-用户模式"><a href="#0x02-qemu-用户模式" class="headerlink" title="0x02 qemu-用户模式"></a>0x02 qemu-用户模式</h1><p>在user mode下使用qemu执行程序有两种情况一是目标程序为<strong>静态链接</strong>那么可以直接使用qemu。另一种是目标程序依赖于<strong>动态链接</strong>库,这时候就需要我们来<strong>指明库的位置</strong>,否则目标程序回到系统<code>/lib</code>文件下寻找共享库文件。<br><em>《揭秘家用路由器0day》</em> 这本书里面,他给出的方法是:<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> cp $(which qemu-mipsel) ./</span><br><span class="line"><span class="meta">$</span> sudo chroot . ./qemu-mipsel ./usr/sbin/miniupnpd</span><br></pre></td></tr></table></figure></p>
<p>他把qemu-mipsel复制到固件文件目录下然后<code>chroot</code>命令改变qemu执行的根目录到当前目录按理说此时应该可以找到依赖库,但是结果却是<code>chroot: failed to run command ./qemu-mipsel: No such file or directory</code></p>
<p>在网上找到了<a href="https://xz.aliyun.com/t/3826" target="_blank" rel="noopener">解决方法</a>:需要安装使用 <strong>qemu-mips-static</strong> 才可以<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> apt-get install qemu binfmt-support qemu-user-static</span><br><span class="line"><span class="meta">$</span> cp $(which qemu-mipsel-static ) ./</span><br><span class="line"><span class="meta">$</span> sudo chroot . ./qemu-mipsel-static ./usr/sbin/miniupnpd</span><br></pre></td></tr></table></figure></p>
<p>这里还可利用<code>-E</code>用来设置环境变量,<code>LD_PRELOAD &quot;./lib&quot;</code>用来劫持系统调用,另外还有<code>-g</code>开启调试模式</p>
<p>除此之外,也在<a href="https://wiki.x10sec.org/pwn/arm/environment/" target="_blank" rel="noopener">CTF-WIKI</a>上找到了另一种方法:使用 <strong>qemu-mips 的 -L 参数</strong>指定路由器的根目录<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> qemu-mipsel -L . ./usr/sbin/miniupnpd</span><br></pre></td></tr></table></figure></p>
<h2 id="模拟miniupnp"><a href="#模拟miniupnp" class="headerlink" title="模拟miniupnp"></a>模拟miniupnp</h2><p>由于没有指定参数所以这里miniupnpd只把usage和notes打印给我们了<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">Usage:</span><br><span class="line"> ./usr/sbin/miniupnpd [-f config_file] [-i ext_ifname] [-o ext_ip]</span><br><span class="line"> [-a listening_ip] [-p port] [-d] [-U] [-S] [-N]</span><br><span class="line"> [-u uuid] [-s serial] [-m model_number]</span><br><span class="line"> [-t notify_interval] [-P pid_filename]</span><br><span class="line"> [-B down up] [-w url] [-r clean_ruleset_interval]</span><br><span class="line"> [-A "permission rule"] [-b BOOTID]</span><br><span class="line"></span><br><span class="line">Notes:</span><br><span class="line"> There can be one or several listening_ips.</span><br><span class="line"> Notify interval is in seconds. Default is 30 seconds.</span><br><span class="line"> Default pid file is '/var/run/miniupnpd.pid'.</span><br><span class="line"> Default config file is '/etc/miniupnpd.conf'.</span><br><span class="line"> With -d miniupnpd will run as a standard program.</span><br><span class="line"> -S sets "secure" mode : clients can only add mappings to their own ip</span><br><span class="line"> -U causes miniupnpd to report system uptime instead of daemon uptime.</span><br><span class="line"> -N enables NAT-PMP functionality.</span><br><span class="line"> -B sets bitrates reported by daemon in bits per second.</span><br><span class="line"> -w sets the presentation url. Default is http address on port 80</span><br><span class="line"> -A use following syntax for permission rules :</span><br><span class="line"> (allow|deny) (external port range) ip/mask (internal port range)</span><br><span class="line"> examples :</span><br><span class="line"> "allow 1024-65535 192.168.1.0/24 1024-65535"</span><br><span class="line"> "deny 0-65535 0.0.0.0/0 0-65535"</span><br><span class="line"> -b sets the value of BOOTID.UPNP.ORG SSDP header</span><br><span class="line"> -h prints this help and quits.</span><br></pre></td></tr></table></figure></p>
<p>根据miniupnpd的启动文件<code>/etc/init.d/miniupnpd</code>,小米使用了启动脚本来配置<code>service_start /usr/sbin/miniupnpd -f conffile -d</code><br>其配置文件connfile如下所示<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">ext_ifname=eth0.2</span><br><span class="line">listening_ip=br-lan</span><br><span class="line">port=5351</span><br><span class="line">enable_natpmp=yes</span><br><span class="line">enable_upnp=yes</span><br><span class="line">secure_mode=no</span><br><span class="line">system_uptime=yes</span><br><span class="line">lease_file=/tmp/upnp.leases</span><br><span class="line">bitrate_down=8388608</span><br><span class="line">bitrate_up=4194304</span><br><span class="line">uuid=e1f3a0ec-d9d4-4317-a14b-130cdd18d092</span><br><span class="line">allow 1024-65535 0.0.0.0/0 1024-65535</span><br><span class="line">deny 0-65535 0.0.0.0/0 0-65535</span><br></pre></td></tr></table></figure></p>
<ul>
<li style="list-style: none"><input type="checkbox"> 可见因路由器的特殊性,具有两张网卡(eth0.2&amp;br-lan)暂时我还没想出应该怎么解决是否采用qemu虚拟机配置网络可以解决呢反正我采用下面这种粗暴的方式是不可以的(直接指定配置文件)<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> sudo qemu-mipsel -L . ./usr/sbin/miniupnpd -f ../../MiniUPnP/miniupnpd.conf -d</span><br><span class="line">miniupnpd[7687]: system uptime is 5652 seconds</span><br><span class="line">miniupnpd[7687]: iptc_init() failed : iptables who? (do you need to insmod?)</span><br><span class="line">miniupnpd[7687]: Failed to init redirection engine. EXITING</span><br></pre></td></tr></table></figure>
</li>
</ul>
<hr>
<h1 id="0x03-qemu-系统模式"><a href="#0x03-qemu-系统模式" class="headerlink" title="0x03 qemu-系统模式"></a>0x03 qemu-系统模式</h1><p>系统模式命令格式:<code>$qemu system-mips [option][disk_image]</code></p>
<h2 id="MIPS系统网络配置"><a href="#MIPS系统网络配置" class="headerlink" title="MIPS系统网络配置"></a>MIPS系统网络配置</h2><p>下载mips系统内核和虚拟机镜像 <a href="https://people.debian.org/~aurel32/qemu/" target="_blank" rel="noopener">https://people.debian.org/~aurel32/qemu/</a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><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">To use this image, you need to install QEMU 1.1.0 (or later). Start QEMU</span><br><span class="line">with the following arguments for a 32-bit machine:</span><br><span class="line"> - qemu-system-mipsel -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append &quot;root=/dev/sda1 console=tty0&quot;</span><br><span class="line"> - qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append &quot;root=/dev/sda1 console=tty0&quot;</span><br></pre></td></tr></table></figure></p>
<p><strong>1. 安装依赖文件</strong><code>apt-get install uml-utilities bridge-utils</code></p>
<p><strong>2. 修改主机网络配置</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">auto lo</span><br><span class="line">iface lo inet loopback</span><br><span class="line"></span><br><span class="line">auto ens33</span><br><span class="line">iface eth0 inet dhcp</span><br><span class="line"></span><br><span class="line">#auto br0</span><br><span class="line">iface br0 inet dhcp</span><br><span class="line"> bridge_ports ens33</span><br><span class="line"> bridge_maxwait 0</span><br></pre></td></tr></table></figure></p>
<p><strong>3. 修改qemu网络接口启动脚本</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">$ sudo vim /etc/qemu-ifup </span><br><span class="line">$ sudo chmod a+x /etc/qemu-ifup</span><br><span class="line">#!/bin/sh</span><br><span class="line">echo &quot;Executing /etc/qemu-ifup&quot;</span><br><span class="line">echo &quot;Bringing $1 for bridged mode...&quot;</span><br><span class="line">sudo /sbin/ifconfig $1 0.0.0.0 promisc up</span><br><span class="line">echo &quot;Adding $1 to br0...&quot;</span><br><span class="line">sudo /sbin/brctl addif br0 $1</span><br><span class="line">sleep 3</span><br></pre></td></tr></table></figure></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo /etc/init.d/networking restart</span><br></pre></td></tr></table></figure>
<p><strong>4. qemu启动配置</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sudo ifdown ens33</span><br><span class="line">$ sudo ifup br0</span><br></pre></td></tr></table></figure></p>
<p><strong>5. 启动mips虚拟机</strong><br><code>sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append &quot;root=/dev/sda1 console=tty0&quot; -net nic,macaddr=00:16:3e:00:00:01 -net tap -nographic</code></p>
<p>我自闭了ubuntu18根本没法联网于是我用了ubuntu14.0</p>
<hr>
<h1 id="0x04-在mips虚拟机中调试"><a href="#0x04-在mips虚拟机中调试" class="headerlink" title="0x04 在mips虚拟机中调试"></a>0x04 在mips虚拟机中调试</h1><p>现在通过上面的配置我得到了这样一台虚拟机并通过ssh连接上去。<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><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">root@debian-mipsel:/home/user/mi_wifi_r3_112# ifconfig</span><br><span class="line">eth1 Link encap:Ethernet HWaddr 00:16:3e:00:00:01</span><br><span class="line"> inet addr:192.168.31.246 Bcast:192.168.31.255 Mask:255.255.255.0</span><br><span class="line"> inet6 addr: fe80::216:3eff:fe00:1/64 Scope:Link</span><br><span class="line"> UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1</span><br><span class="line"> RX packets:89377 errors:75 dropped:360 overruns:0 frame:0</span><br><span class="line"> TX packets:9114 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line"> collisions:0 txqueuelen:1000</span><br><span class="line"> RX bytes:103978997 (99.1 MiB) TX bytes:924287 (902.6 KiB)</span><br><span class="line"> Interrupt:10 Base address:0x1020</span><br><span class="line"></span><br><span class="line">lo Link encap:Local Loopback</span><br><span class="line"> inet addr:127.0.0.1 Mask:255.0.0.0</span><br><span class="line"> inet6 addr: ::1/128 Scope:Host</span><br><span class="line"> UP LOOPBACK RUNNING MTU:16436 Metric:1</span><br><span class="line"> RX packets:8 errors:0 dropped:0 overruns:0 frame:0</span><br><span class="line"> TX packets:8 errors:0 dropped:0 overruns:0 carrier:0</span><br><span class="line"> collisions:0 txqueuelen:0</span><br><span class="line"> RX bytes:560 (560.0 B) TX bytes:560 (560.0 B)</span><br></pre></td></tr></table></figure></p>
<p>已经把我的小米固件全部上传到这个虚拟机中<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# ls</span><br><span class="line">bin data dev etc extdisks lib libnvram-faker.so mnt opt overlay proc qemu-mipsel-static readonly rom root sbin sys tmp userdisk usr var www</span><br></pre></td></tr></table></figure></p>
<p>和用户模式一样还是使用chroot因为目标二进制是和固件的库链接的很可能不能跟Debian的共享库一起工作。<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# chroot . ./usr/sbin/miniupnpd</span><br><span class="line">Usage:</span><br><span class="line"> ./usr/sbin/miniupnpd [-f config_file] [-i ext_ifname] [-o ext_ip]</span><br><span class="line"> [-a listening_ip] [-p port] [-d] [-U] [-S] [-N]</span><br><span class="line"> [-u uuid] [-s serial] [-m model_number]</span><br><span class="line"> [-t notify_interval] [-P pid_filename]</span><br><span class="line"> [-B down up] [-w url] [-r clean_ruleset_interval]</span><br><span class="line"> [-A "permission rule"] [-b BOOTID]</span><br><span class="line"></span><br><span class="line">Notes:</span><br><span class="line"> There can be one or several listening_ips.</span><br><span class="line"> Notify interval is in seconds. Default is 30 seconds.</span><br><span class="line"> Default pid file is '/var/run/miniupnpd.pid'.</span><br><span class="line"> Default config file is '/etc/miniupnpd.conf'.</span><br><span class="line"> With -d miniupnpd will run as a standard program.</span><br><span class="line"> -S sets "secure" mode : clients can only add mappings to their own ip</span><br><span class="line"> -U causes miniupnpd to report system uptime instead of daemon uptime.</span><br><span class="line"> -N enables NAT-PMP functionality.</span><br><span class="line"> -B sets bitrates reported by daemon in bits per second.</span><br><span class="line"> -w sets the presentation url. Default is http address on port 80</span><br><span class="line"> -A use following syntax for permission rules :</span><br><span class="line"> (allow|deny) (external port range) ip/mask (internal port range)</span><br><span class="line"> examples :</span><br><span class="line"> "allow 1024-65535 192.168.1.0/24 1024-65535"</span><br><span class="line"> "deny 0-65535 0.0.0.0/0 0-65535"</span><br><span class="line"> -b sets the value of BOOTID.UPNP.ORG SSDP header</span><br><span class="line"> -h prints this help and quits.</span><br></pre></td></tr></table></figure></p>
<p>直接运行起来还是只打印出usage这里我注意到之前忽视的地方<code>Default config file is &#39;/etc/miniupnpd.conf&#39;.</code>,所以我不再使用<code>-f</code>参数来指定,而是把配置文件放在默认目录下,在小米路由器里,<code>ext_ifname</code>是外部ip<code>listening_ip</code>是内部ip。但是我这里还没有开启两个所以都赋值为一张网卡。<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">ext_ifname=eth1</span><br><span class="line">listening_ip=eth1</span><br><span class="line">port=5351</span><br><span class="line">enable_natpmp=yes</span><br><span class="line">enable_upnp=yes</span><br><span class="line">secure_mode=no</span><br><span class="line">system_uptime=yes</span><br><span class="line">lease_file=/tmp/upnp.leases</span><br><span class="line">bitrate_down=8388608</span><br><span class="line">bitrate_up=4194304</span><br><span class="line">uuid=e1f3a0ec-d9d4-4317-a14b-130cdd18d092</span><br><span class="line">allow 1024-65535 0.0.0.0/0 1024-65535</span><br><span class="line">deny 0-65535 0.0.0.0/0 0-65535</span><br></pre></td></tr></table></figure></p>
<p>在这个配置下运行miniupnp还是被告知<code>daemon(): No such file or directory</code><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# chroot . ./usr/sbin/miniupnpd</span><br><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# daemon(): No such file or directory</span><br></pre></td></tr></table></figure></p>
<p>我起初猜测是因为缺乏<code>NVRAM</code></p>
<blockquote>
<p>在运行系统服务如Web服务器或UPnP守护进程时缺乏NVRAM。非易失性RAM通常是包含配置参数的设备快速存储器的一个分区。当一个守护进程启动时它通常会尝试查询NVRAM获取其运行时配置信息。有时一个守护进程会查询NVRAM的几十甚至上百个参数。</p>
</blockquote>
<p>于是我运行二进制程序时使用LD_PRELOAD对nvram-faker库进行预加载。它会拦截通常由libnvram.so提供的<code>nvram_get()</code>调用。nvram-faker会查询你提供的一个INI风格的配置文件而不是试图查询NVRAM。<br>这里有一个链接:<a href="https://github.com/zcutlip/nvram-faker" target="_blank" rel="noopener">https://github.com/zcutlip/nvram-faker</a><br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# chroot . /bin/sh -c "LD_PRELOAD=/libnvram-faker.so /usr/sbin/miniupnpd"</span><br><span class="line">root@debian-mipsel:/home/user/mi_wifi_r3_112# daemon(): No such file or directory</span><br></pre></td></tr></table></figure></p>
<p>问题依然存在daemon是在miniupnpd中常出现的词猜测会不会某些函数没有实现这部分会比较麻烦需要反汇编。<br>但是我们不是可以拿到路由器的shell吗干嘛还要用qemu模拟再调试直接上真机</p>
<hr>
<h1 id="0x05-设备上调试程序"><a href="#0x05-设备上调试程序" class="headerlink" title="0x05 设备上调试程序"></a>0x05 设备上调试程序</h1><blockquote>
<p>1、有shell权限<br>2、有静态编译的gdbserver或者gdb</p>
</blockquote>
<p>只要满足上面两个条件,我们就可以通过在路由器上运行<code>gdbserver_mipsle --attach 0.0.0.0:port PID</code> 以及 在你的电脑上使用 <strong>gdb-multiarch</strong> 进行调试(先指定架构然后使用remote功能)轻松地调试设备上地mips程序。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; set architecture mips (但大多数情况下这一步可以省略, 似乎 pwndbg 能自动识别架构)</span><br><span class="line">pwndbg&gt; target remote localhost:1234</span><br></pre></td></tr></table></figure></p>
<p>能根据固件中的bin得知这是一个小端mips指令集的设备gdbserver也不用自己编译直接下载编译好的: <a href="https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver" target="_blank" rel="noopener">https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver</a><br>把gdbserver.mipsbe通过tftp上传到路由器的/tmp目录下然后找到目标程序PID<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">root@XiaoQiang:/# ps |grep miniupnp</span><br><span class="line">12517 root 1772 S grep miniupnp</span><br><span class="line">28284 root 1496 S /usr/sbin/miniupnpd -f /var/etc/miniupnpd.conf</span><br></pre></td></tr></table></figure></p>
<p><strong>gdbserver attach</strong>这个进程,就可以通过<strong>gdb</strong>或者<strong>IDA</strong>远程调试这个程序</p>
</div>
<div>
<div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
<div>您的支持将鼓励我继续创作!</div>
<button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
<span>打赏</span>
</button>
<div id="QR" style="display: none;">
<div id="wechat" style="display: inline-block">
<img id="wechat_qr" src="/images/Wechatpay.png" alt="Cool-Y 微信支付">
<p>微信支付</p>
</div>
<div id="alipay" style="display: inline-block">
<img id="alipay_qr" src="/images/Alipay.png" alt="Cool-Y 支付宝">
<p>支付宝</p>
</div>
</div>
</div>
</div>
<div>
<ul class="post-copyright">
<li class="post-copyright-author">
<strong>本文作者:</strong>
Cool-Y
</li>
<li class="post-copyright-link">
<strong>本文链接:</strong>
<a href="https://cool-y.github.io/2019/07/25/Debug-a-router-firmware/" title="远程调试小米路由器固件">https://cool-y.github.io/2019/07/25/Debug-a-router-firmware/</a>
</li>
<li class="post-copyright-license">
<strong>版权声明: </strong>
本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 3.0</a> 许可协议。转载请注明出处!
</li>
</ul>
</div>
<footer class="post-footer">
<div class="post-tags">
<a href="/tags/小米/" rel="tag"># 小米</a>
<a href="/tags/路由器/" rel="tag"># 路由器</a>
<a href="/tags/调试/" rel="tag"># 调试</a>
</div>
<div class="post-widgets">
<div id="needsharebutton-postbottom">
<span class="btn">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</span>
</div>
</div>
<div class="post-nav">
<div class="post-nav-next post-nav-item">
<a href="/2019/07/24/获取固件/" rel="next" title="获取固件的几种方法">
<i class="fa fa-chevron-left"></i> 获取固件的几种方法
</a>
</div>
<span class="post-nav-divider"></span>
<div class="post-nav-prev post-nav-item">
<a href="/2019/10/25/PWNtw-start/" rel="prev" title="【Pwnable.tw】start">
【Pwnable.tw】start <i class="fa fa-chevron-right"></i>
</a>
</div>
</div>
</footer>
</div>
</article>
<div class="post-spread">
</div>
</div>
</div>
<div class="comments" id="comments">
<div id="gitalk-container"></div>
</div>
</div>
<div class="sidebar-toggle">
<div class="sidebar-toggle-line-wrap">
<span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
</div>
</div>
<aside id="sidebar" class="sidebar">
<div id="sidebar-dimmer"></div>
<div class="sidebar-inner">
<ul class="sidebar-nav motion-element">
<li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
文章目录
</li>
<li class="sidebar-nav-overview" data-target="site-overview-wrap">
站点概览
</li>
</ul>
<section class="site-overview-wrap sidebar-panel">
<div class="site-overview">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image" src="/images/avatar.png" alt="Cool-Y">
<p class="site-author-name" itemprop="name">Cool-Y</p>
<p class="site-description motion-element" itemprop="description">Juice is temporary but Sauce is forever</p>
</div>
<nav class="site-state motion-element">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">31</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/categories/index.html">
<span class="site-state-item-count">7</span>
<span class="site-state-item-name">分类</span>
</a>
</div>
<div class="site-state-item site-state-tags">
<a href="/tags/index.html">
<span class="site-state-item-count">55</span>
<span class="site-state-item-name">标签</span>
</a>
</div>
</nav>
<div class="feed-link motion-element">
<a href="/atom.xml" rel="alternate">
<i class="fa fa-rss"></i>
RSS
</a>
</div>
<div class="links-of-author motion-element">
<span class="links-of-author-item">
<a href="https://github.com/Cool-Y" target="_blank" title="GitHub">
<i class="fa fa-fw fa-github"></i>GitHub</a>
</span>
<span class="links-of-author-item">
<a href="mailto:cool.yim@whu.edu.cn" target="_blank" title="E-Mail">
<i class="fa fa-fw fa-envelope"></i>E-Mail</a>
</span>
<span class="links-of-author-item">
<a href="https://www.instagram.com/yan__han/" target="_blank" title="Instagram">
<i class="fa fa-fw fa-instagram"></i>Instagram</a>
</span>
</div>
<div id="music163player">
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="330" height="110" src="//music.163.com/outchain/player?type=4&id=334277093&auto=1&height=90"></iframe>
</div>
</div>
</section>
<!--noindex-->
<section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
<div class="post-toc">
<div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#0x00-背景与简介"><span class="nav-text">0x00 背景与简介</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#REF"><span class="nav-text">REF</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#0x01-基础条件"><span class="nav-text">0x01 基础条件</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#0x02-qemu-用户模式"><span class="nav-text">0x02 qemu-用户模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#模拟miniupnp"><span class="nav-text">模拟miniupnp</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#0x03-qemu-系统模式"><span class="nav-text">0x03 qemu-系统模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#MIPS系统网络配置"><span class="nav-text">MIPS系统网络配置</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#0x04-在mips虚拟机中调试"><span class="nav-text">0x04 在mips虚拟机中调试</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#0x05-设备上调试程序"><span class="nav-text">0x05 设备上调试程序</span></a></li></ol></div>
</div>
</section>
<!--/noindex-->
</div>
</aside>
</div>
</main>
<footer id="footer" class="footer">
<div class="footer-inner">
<div class="copyright">&copy; 2019 &mdash; <span itemprop="copyrightYear">2021</span>
<span class="with-love">
<i class="fa fa-user"></i>
</span>
<span class="author" itemprop="copyrightHolder">Cool-Y</span>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-area-chart"></i>
</span>
<span title="Site words total count">105.1k</span>
</div>
<div class="powered-by"><a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>
<div class="busuanzi-count">
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<span class="site-uv">
<i class="fa fa-user"></i>
<span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
</span>
<span class="site-pv">
<i class="fa fa-eye"></i>
<span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
</span>
</div>
</div>
</footer>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span id="scrollpercent"><span>0</span>%</span>
</div>
<div id="needsharebutton-float">
<span class="btn">
<i class="fa fa-share-alt" aria-hidden="true"></i>
</span>
</div>
</div>
<script type="text/javascript">
if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
window.Promise = null;
}
</script>
<script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
<script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
<script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>
<!-- LOCAL: You can save these files to your site and update links -->
<link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
<!-- END LOCAL -->
<script type="text/javascript">
function renderGitalk(){
var gitalk = new Gitalk({
owner: 'Cool-Y',
repo: 'gitment-comments',
clientID: '180955a2c3ae3d966d9a',
clientSecret: '1c5db4da72df5e6fc318d12afe5f4406f7c54343',
admin: 'Cool-Y',
id: decodeURI(location.pathname),
distractionFreeMode: 'true'
});
gitalk.render('gitalk-container');
}
renderGitalk();
</script>
<script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
<script>AV.initialize("CnxMogaLcXQrm9Q03lF8XH7j-gzGzoHsz", "EHqNuJ6AYvuHnY6bN6w2SMXl");</script>
<script>
function showTime(Counter) {
var query = new AV.Query(Counter);
var entries = [];
var $visitors = $(".leancloud_visitors");
$visitors.each(function () {
entries.push( $(this).attr("id").trim() );
});
query.containedIn('url', entries);
query.find()
.done(function (results) {
var COUNT_CONTAINER_REF = '.leancloud-visitors-count';
if (results.length === 0) {
$visitors.find(COUNT_CONTAINER_REF).text(0);
return;
}
for (var i = 0; i < results.length; i++) {
var item = results[i];
var url = item.get('url');
var time = item.get('time');
var element = document.getElementById(url);
$(element).find(COUNT_CONTAINER_REF).text(time);
}
for(var i = 0; i < entries.length; i++) {
var url = entries[i];
var element = document.getElementById(url);
var countSpan = $(element).find(COUNT_CONTAINER_REF);
if( countSpan.text() == '') {
countSpan.text(0);
}
}
})
.fail(function (object, error) {
console.log("Error: " + error.code + " " + error.message);
});
}
function addCount(Counter) {
var $visitors = $(".leancloud_visitors");
var url = $visitors.attr('id').trim();
var title = $visitors.attr('data-flag-title').trim();
var query = new AV.Query(Counter);
query.equalTo("url", url);
query.find({
success: function(results) {
if (results.length > 0) {
var counter = results[0];
counter.fetchWhenSave(true);
counter.increment("time");
counter.save(null, {
success: function(counter) {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(counter.get('time'));
},
error: function(counter, error) {
console.log('Failed to save Visitor num, with error message: ' + error.message);
}
});
} else {
var newcounter = new Counter();
/* Set ACL */
var acl = new AV.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
newcounter.setACL(acl);
/* End Set ACL */
newcounter.set("title", title);
newcounter.set("url", url);
newcounter.set("time", 1);
newcounter.save(null, {
success: function(newcounter) {
var $element = $(document.getElementById(url));
$element.find('.leancloud-visitors-count').text(newcounter.get('time'));
},
error: function(newcounter, error) {
console.log('Failed to create');
}
});
}
},
error: function(error) {
console.log('Error:' + error.code + " " + error.message);
}
});
}
$(function() {
var Counter = AV.Object.extend("Counter");
if ($('.leancloud_visitors').length == 1) {
addCount(Counter);
} else if ($('.post-title-link').length > 1) {
showTime(Counter);
}
});
</script>
<script>
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
</script>
<link rel="stylesheet" href="/lib/needsharebutton/needsharebutton.css">
<script src="/lib/needsharebutton/needsharebutton.js"></script>
<script>
pbOptions = {};
pbOptions.iconStyle = "box";
pbOptions.boxForm = "horizontal";
pbOptions.position = "bottomCenter";
pbOptions.networks = "Weibo,Wechat,Douban,QQZone,Twitter,Facebook";
new needShareButton('#needsharebutton-postbottom', pbOptions);
flOptions = {};
flOptions.iconStyle = "box";
flOptions.boxForm = "horizontal";
flOptions.position = "middleRight";
flOptions.networks = "Weibo,Wechat,Douban,QQZone,Twitter,Facebook";
new needShareButton('#needsharebutton-float', flOptions);
</script>
<script type="text/javascript" src="/js/src/js.cookie.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/scroll-cookie.js?v=5.1.4"></script>
</body>
</html>