Site updated: 2019-03-30 17:39:53
This commit is contained in:
parent
820586763b
commit
6512a09ec2
@ -96,7 +96,7 @@
|
||||
<meta property="og:image" content="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553858953/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B77.png">
|
||||
<meta property="og:image" content="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937461/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B79.png">
|
||||
<meta property="og:image" content="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937531/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B711.png">
|
||||
<meta property="og:updated_time" content="2019-03-30T09:36:07.633Z">
|
||||
<meta property="og:updated_time" content="2019-03-30T09:39:39.837Z">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="逆向工程与软件破解">
|
||||
<meta name="twitter:description" content="软件保护方式 功能限制 时间限制 运行时长限制 使用日期限制 使用次数限制 警告窗口 分析工具 静态分析工具 IDA W32Dasm lordPE Resource Hacker 动态分析工具 OllyDbg WinDbg 对抗分析技术 反静态分析技术 花指令 自修改代码技术 多态技术 变形技术 虚拟机保护技术 反动态分析技术 检测调试状态 检测用户态调试器">
|
||||
@ -517,27 +517,27 @@
|
||||
</ul>
|
||||
<h2 id="爆破"><a href="#爆破" class="headerlink" title="爆破"></a>爆破</h2><h3 id="查找显示注册结果相关代码"><a href="#查找显示注册结果相关代码" class="headerlink" title="查找显示注册结果相关代码"></a>查找显示注册结果相关代码</h3><p>当输入错误验证码时,程序会输出“Bad Boy”,因此我们将程序拖入IDA,以流程图显示函数内部的跳转。查找“Bad Boy”字符串,我们可以定位到显示注册结果的相关代码:<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553772615/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B71.png" alt></p>
|
||||
<h3 id="查找注册码验证相关代码"><a href="#查找注册码验证相关代码" class="headerlink" title="查找注册码验证相关代码"></a>查找注册码验证相关代码</h3><p>用鼠标选中程序分支点,按空格切换回汇编指令界面<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553773066/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B72.png" alt></p>
|
||||
<p>可以看到,这条指令位于PE文件的.text节,并且IDA已经自动将地址转换为运行时的内存地址VA:004010F9</p>
|
||||
<p>可以看到,这条指令位于PE文件的.text节,并且IDA已经自动将地址转换为运行时的内存地址<code>VA:004010F9</code></p>
|
||||
<h3 id="修改程序跳转"><a href="#修改程序跳转" class="headerlink" title="修改程序跳转"></a>修改程序跳转</h3><ul>
|
||||
<li>现在关闭IDA,换用OllyDbg进行动态调试来看看程序时如何分支跳转的Ctrl+G直接跳到由IDA得到的<code>VA:004010F9</code>处查看那条引起程序分支的关键指令</li>
|
||||
<li>现在关闭IDA,换用OllyDbg进行动态调试来看看程序时如何分支跳转的<code>Ctrl+G</code>直接跳到由IDA得到的<code>VA:004010F9</code>处查看那条引起程序分支的关键指令</li>
|
||||
<li>选中这条指令,按F2设置断点,再按F9运行程序,这时候控制权会回到程序,OllyDbg暂时挂起。到程序提示输入名字和序列号,随意输入(名字大于五个字节),点击ok后,OllyDbg会重新中断程序,收回控制权,如图:<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775053/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B74.png" alt></li>
|
||||
<li><p>验证函数的返回值存于EAX寄存器中,if语句通过以下两条指令执行</p>
|
||||
<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">cmp eax,ecx</span><br><span class="line">jnz xxxxxxx</span><br></pre></td></tr></table></figure>
|
||||
</li>
|
||||
<li><p>也就是说,当序列号输入错误时,EAX中的值为0,跳转将被执行。<br>如果我们把jnz这条指令修改为jz,那么整个程序的逻辑就会反过来。<br>双击jnz这条指令,将其改为jz,单击”汇编”将其写入内存<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775817/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B75.png" alt><br>可以看到此时程序执行了相反的路径</p>
|
||||
<li><p>也就是说,当序列号输入错误时,EAX中的值为0,跳转将被执行。<br>如果我们把<code>jnz</code>这条指令修改为<code>jz</code>,那么整个程序的逻辑就会反过来。<br>双击<code>jnz</code>这条指令,将其改为<code>jz</code>,单击”汇编”将其写入内存<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775817/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B75.png" alt><br>可以看到此时程序执行了相反的路径</p>
|
||||
</li>
|
||||
<li><p>上面只是在内存中修改程序,我们还需要在二进制文件中也修改相应的字节,这里考察VA与文件地址之间的关系</p>
|
||||
</li>
|
||||
<li>用LordPE打开.exe文件,查看PE文件的节信息<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553776239/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B76.png" alt><br>根据VA与文件地址的换算公式:<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">文件偏移地址 = VA - Image Base - 节偏移</span><br><span class="line"> = 0x004010F9 - 0x00400000 - 0</span><br><span class="line"> = 0x10F9</span><br></pre></td></tr></table></figure>
|
||||
</li>
|
||||
</ul>
|
||||
<p>也就是说,这条指令在PE文件中位于10F9字节处,使用010Editer打开crack.exe,将这一字节的75(JNZ)改为74(JZ),保存后重新执行,破解成功!</p>
|
||||
<p>也就是说,这条指令在PE文件中位于<code>10F9</code>字节处,使用010Editer打开crack.exe,将这一字节的<code>75(JNZ)`</code>改为<code>74(JZ)`</code>,保存后重新执行,破解成功!</p>
|
||||
<h2 id="编写注册机"><a href="#编写注册机" class="headerlink" title="编写注册机"></a>编写注册机</h2><h3 id="查找显示注册结果相关代码-1"><a href="#查找显示注册结果相关代码-1" class="headerlink" title="查找显示注册结果相关代码"></a>查找显示注册结果相关代码</h3><p>通过查找字符串“good boy”等,我们可以找到显示注册结果的相关代码</p>
|
||||
<h3 id="查找注册码验证相关代码-1"><a href="#查找注册码验证相关代码-1" class="headerlink" title="查找注册码验证相关代码"></a>查找注册码验证相关代码</h3><p>因为检测密钥是否正确时会将结果返回到EAX寄存器中,因此,在检测密钥前必然会对EAX寄存器清空,由此我们可以找到注册码验证的相关代码。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553858953/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B77.png" alt></p>
|
||||
<h3 id="根据注册码验证代码编写注册机"><a href="#根据注册码验证代码编写注册机" class="headerlink" title="根据注册码验证代码编写注册机"></a>根据注册码验证代码编写注册机</h3><p>分析上图算法,按tab键转换为高级语言<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">for ( i = 0; i < v6; v12 = v10 )</span><br><span class="line"> v10 = (v6 + v12) * lpStringa[i++];</span><br><span class="line">if ( (v12 ^ 0xA9F9FA) == atoi(v15) )</span><br><span class="line"> MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);</span><br></pre></td></tr></table></figure></p>
|
||||
<p>可以看出,生成注册码主要在for循环中完成,之后将生成的注册码与输入相比较,判断是否正确。<br>所以,只要能弄明白v6,v12,v10,v15的含义,我们就可以轻松的编写注册机。<br>打开ollybdg,在进入循环之前设下断点,动态调试程序<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></pre></td><td class="code"><pre><span class="line">004010CC |> /8B4D 10 |mov ecx,[arg.3] //此时ecx为name</span><br><span class="line">004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908</span><br><span class="line">004010D2 |. 03D3 |add edx,ebx //edx加上name的长度(ebx)</span><br><span class="line">004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h</span><br><span class="line">004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx</span><br><span class="line">004010DB |. 40 |inc eax //eax加1(初始为0)</span><br><span class="line">004010DC |. 894D 0C |mov [arg.2],ecx</span><br><span class="line">004010DF |. 3BC3 |cmp eax,ebx //循环是否结束</span><br></pre></td></tr></table></figure></p>
|
||||
<p>arg.3为输入的name,arg.2初始为0x1908,ebx为name的长度,eax每次循环加1直到等于长度<br>因此,我们可以对参数的含义进行解释如下<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></pre></td><td class="code"><pre><span class="line">v12 = 6408; //0x1908</span><br><span class="line">v10 = 6408; //0x1908</span><br><span class="line">v6 = len(name);</span><br><span class="line">v12 = input_serial;</span><br><span class="line">for ( i = 0; i < v6; i++ ){</span><br><span class="line"> v12 = v10;</span><br><span class="line"> v10 = (v6 + v12) * lpStringa[i];</span><br><span class="line">}</span><br><span class="line">if ((v12 ^ 0xA9F9FA) == atoi(v15)){</span><br><span class="line"> MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
|
||||
<p>可见,v12^0xA9F9FA的结果即是正确的注册码,我们编写一个<a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553937750/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/reg.cpp" target="_blank" rel="noopener">简单的程序</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><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">#include <iostream></span><br><span class="line">#include<stdio.h></span><br><span class="line"></span><br><span class="line">using namespace::std;</span><br><span class="line">int main(){</span><br><span class="line"> int v12;</span><br><span class="line"> int v10 = 6408; //0x1908</span><br><span class="line"> string name;</span><br><span class="line"> cout << "请输入name: ";</span><br><span class="line"> cin >> name;</span><br><span class="line"> int len = name.size();</span><br><span class="line"> for(int i = 0; i < len+1; i++ ){</span><br><span class="line"> v12 = v10;</span><br><span class="line"> v10 = (len + v12) * name[i];</span><br><span class="line"> }</span><br><span class="line"> cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;</span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
|
||||
<p>可以看出,生成注册码主要在for循环中完成,之后将生成的注册码与输入相比较,判断是否正确。<br>所以,只要能弄明白<code>v6,v12,v10,v15</code>的含义,我们就可以轻松的编写注册机。<br>打开ollybdg,在进入循环之前设下断点,动态调试程序<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></pre></td><td class="code"><pre><span class="line">004010CC |> /8B4D 10 |mov ecx,[arg.3] //此时ecx为name</span><br><span class="line">004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908</span><br><span class="line">004010D2 |. 03D3 |add edx,ebx //edx加上name的长度(ebx)</span><br><span class="line">004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h</span><br><span class="line">004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx</span><br><span class="line">004010DB |. 40 |inc eax //eax加1(初始为0)</span><br><span class="line">004010DC |. 894D 0C |mov [arg.2],ecx</span><br><span class="line">004010DF |. 3BC3 |cmp eax,ebx //循环是否结束</span><br></pre></td></tr></table></figure></p>
|
||||
<p><code>arg.3</code>为输入的<code>name</code>,<code>arg.2</code>初始为<code>0x1908</code>,<code>ebx</code>为<code>name</code>的长度,<code>eax</code>每次循环加1直到等于长度<br>因此,我们可以对参数的含义进行解释如下<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></pre></td><td class="code"><pre><span class="line">v12 = 6408; //0x1908</span><br><span class="line">v10 = 6408; //0x1908</span><br><span class="line">v6 = len(name);</span><br><span class="line">v12 = input_serial;</span><br><span class="line">for ( i = 0; i < v6; i++ ){</span><br><span class="line"> v12 = v10;</span><br><span class="line"> v10 = (v6 + v12) * lpStringa[i];</span><br><span class="line">}</span><br><span class="line">if ((v12 ^ 0xA9F9FA) == atoi(v15)){</span><br><span class="line"> MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
|
||||
<p>可见,<code>v12^0xA9F9FA</code>的结果即是正确的注册码,我们编写一个<a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553937750/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/reg.cpp" target="_blank" rel="noopener">简单的程序</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><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">#include <iostream></span><br><span class="line">#include<stdio.h></span><br><span class="line"></span><br><span class="line">using namespace::std;</span><br><span class="line">int main(){</span><br><span class="line"> int v12;</span><br><span class="line"> int v10 = 6408; //0x1908</span><br><span class="line"> string name;</span><br><span class="line"> cout << "请输入name: ";</span><br><span class="line"> cin >> name;</span><br><span class="line"> int len = name.size();</span><br><span class="line"> for(int i = 0; i < len+1; i++ ){</span><br><span class="line"> v12 = v10;</span><br><span class="line"> v10 = (len + v12) * name[i];</span><br><span class="line"> }</span><br><span class="line"> cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;</span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
|
||||
<p>计算出”testname”的对应注册码<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937461/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B79.png" alt><br>注册成功!<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937531/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B711.png" alt></p>
|
||||
<h1 id="实验二:软件反动态调试技术分析"><a href="#实验二:软件反动态调试技术分析" class="headerlink" title="实验二:软件反动态调试技术分析"></a>实验二:软件反动态调试技术分析</h1><h2 id="对象-1"><a href="#对象-1" class="headerlink" title="对象"></a>对象</h2><p><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779243/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/CrackMe1.exe1" target="_blank" rel="noopener">CrackMe1.exe</a> 1641.0 KB<br>无保护措施:无壳、未加密、无反调试措施<br>使用OllyDbg对该程序进行调试时,程序会自动退出</p>
|
||||
<h2 id="要求"><a href="#要求" class="headerlink" title="要求"></a>要求</h2><ol>
|
||||
|
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@
|
||||
<url>
|
||||
<loc>https://cool-y.github.io/2019/03/28/%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C/</loc>
|
||||
|
||||
<lastmod>2019-03-30T09:36:07.633Z</lastmod>
|
||||
<lastmod>2019-03-30T09:39:39.837Z</lastmod>
|
||||
|
||||
</url>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user