﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-jeromewen</title><link>http://www.cppblog.com/jeromewen/</link><description>努力中</description><language>zh-cn</language><lastBuildDate>Fri, 03 Apr 2026 20:25:24 GMT</lastBuildDate><pubDate>Fri, 03 Apr 2026 20:25:24 GMT</pubDate><ttl>60</ttl><item><title>LibTiff 编译过程</title><link>http://www.cppblog.com/jeromewen/archive/2010/04/13/112511.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Tue, 13 Apr 2010 14:30:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2010/04/13/112511.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/112511.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2010/04/13/112511.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/112511.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/112511.html</trackback:ping><description><![CDATA[<p>很意外的原因要用到 LibTiff 这里将编译过程记录下来备忘。<br><a href="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff/</a><br><a href="http://dl.maptools.org/dl/libtiff/">http://dl.maptools.org/dl/libtiff/</a></p>
<p>tiff-3.8.0<br>提示找不到 jpeg.h zlib.h</p>
<p>libtiff/tiffconf.h.vc</p>
<p>42:#undef JPEG_SUPPORT<br>61:#undef PIXARLOG_SUPPORT<br>67:#undef ZIP_SUPPORT</p>
<p>libtiff/Makefile.vc<br>56:#&nbsp;tif_jpeg.obj \<br>64:#&nbsp;tif_pixarlog.obj \<br>76:#&nbsp;tif_zip.obj \</p>
<p>tif_codec.obj : error LNK2001: 无法解析的外部符号 _TIFFInitPixarLog<br>tif_codec.obj : error LNK2001: 无法解析的外部符号 _TIFFInitZIP<br>tif_codec.obj : error LNK2001: 无法解析的外部符号 _TIFFInitJPEG</p>
<p><br>libtiff/tif_codec.c<br>86://&nbsp;&nbsp;&nbsp; { "JPEG",&nbsp;&nbsp;COMPRESSION_JPEG,&nbsp;TIFFInitJPEG },<br>93://&nbsp;&nbsp;&nbsp; { "Deflate",&nbsp;COMPRESSION_DEFLATE,&nbsp;TIFFInitZIP },<br>94://&nbsp;&nbsp;&nbsp; { "AdobeDeflate",&nbsp;&nbsp; COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, <br>95://&nbsp;&nbsp;&nbsp; { "PixarLog",&nbsp;COMPRESSION_PIXARLOG,&nbsp;TIFFInitPixarLog },<br></p><img src ="http://www.cppblog.com/jeromewen/aggbug/112511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2010-04-13 22:30 <a href="http://www.cppblog.com/jeromewen/archive/2010/04/13/112511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>weblogci数据源配置</title><link>http://www.cppblog.com/jeromewen/archive/2006/11/08/14875.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Wed, 08 Nov 2006 12:20:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/11/08/14875.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/14875.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/11/08/14875.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/14875.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/14875.html</trackback:ping><description><![CDATA[<p>一.配置weblogic服务器<br />start menu-&gt;program-&gt;BEA Weblogic Platfrom 8.1-&gt;Configuration Wizard-&gt;Create a new Weblogic-&gt;next-&gt;next-&gt;next-&gt;(user password)next-&gt;(select jdk)next-&gt;(datasource)create<br />二.数据库驱动配置<br />copy mysql-connector-java-3.1.11-bin.jar to %WL_HOME%\<br />在d:\SoftWare\BEA\user_projects\domains\datasource\startWebLogic.cmd的set CLASSPATH=部分加入%WL_HOME%\mysql-connector-java-3.1.11-bin.jar<br />三.配置数据库连接池<br />1.start menu-&gt;program-&gt;BEA Weblogic Platfrom 8.1-&gt;User Projects-&gt;datasource-&gt;Start Server<br />2.打开<a href="http://127.0.0.1:7001/console">http://127.0.0.1:7001/console</a> weblogic 12345678<br />3.datasource-&gt;服务-&gt;JDBC-&gt;连接缓冲池(Connections Pools)-&gt;(配置新的JDBC连接缓冲池)configure a new JDBC Connection Pools<br />4.Database Type 选择mysql驱动为org.gjt.mm.mysql.Driver<br />5.Continue<br />名称:MyJDBC Connection Pool<br />数据库名称:datasource<br />主机名:127.0.0.1<br />端口:3306<br />数据库用户名:<br />密码:<br />确认密码:<br />5.Continue-&gt;Test Driver Configuration<br />6.Create and deploy<br />四.配置数据源<br />1.datasource-&gt;服务-&gt;JDBC-&gt;数据源(Data Source)-&gt;configure a new JDBC Data Source<br />2.<br />名称:MyData Source<br />JNDI名称:MyData Source<br />3.Continue-&gt;Continue-&gt;Create<br />------------测试代码DSTest.java------------------------<br />import java.sql.*;<br />import javax.naming.*;<br />import javax.sql.*;<br />import java.util.Properties;<br />import javax.rmi.PortableRemoteObject;</p>
		<p>public class DSTest{<br /> private static Context getInitialContext(){<br />  String URL="t3://127.0.0.1:7001";<br />  String user="weblogic";<br />  String password="12345678";<br />  Properties prop=null;<br />  Context context=null;<br />  <br />  try{<br />   prop = new Properties();<br />   prop.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");<br />   prop.put(Context.PROVIDER_URL,URL);<br />   prop.put(Context.SECURITY_PRINCIPAL,user);<br />   prop.put(Context.SECURITY_CREDENTIALS,password);<br />   context = new InitialContext(prop);<br />  }<br />  catch(Exception e)<br />  {<br />   e.printStackTrace();<br />  }<br />  return context;<br />  }<br /> <br /> public static void main(String[] args){<br />  DSTest dstest = new DSTest();<br />  <br />  DataSource ds=null;<br />  Context ctx=null;<br />  Connection conn=null;<br />  <br />  try{<br />   ctx = getInitialContext();<br />   ds = (DataSource)ctx.lookup("MyData Source");<br />  }<br />  catch(Exception e){<br />   e.printStackTrace();<br />  }<br />  <br />  Statement stmt=null;<br />  ResultSet rs=null;<br />  <br />  try{<br />   conn = ds.getConnection();<br />   stmt = conn.createStatement();<br />   String sql = "select * from user";<br />   rs = stmt.executeQuery(sql);<br />   <br />   while(rs.next()){<br />    System.out.println("username : " + rs.getString("username"));<br />    System.out.println("password : " + rs.getString("password"));<br />    }<br />  }<br />  catch(SQLException e){<br />   e.printStackTrace();<br />   }<br />  finally{<br />   try{<br />   if(stmt != null) { stmt.close();}<br />   if (conn != null) { conn.close();}<br />   }<br />   catch(SQLException e){<br />    e.printStackTrace();<br />    }<br />  }<br />  }<br />}<br />--------------------------------------------------------------------------------------------<br />set CLASSPATH=%CLASSPATH%;weblogic.jar<br />javac DSTest.java<br />java DSTest<br />pause<br /></p><img src ="http://www.cppblog.com/jeromewen/aggbug/14875.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-11-08 20:20 <a href="http://www.cppblog.com/jeromewen/archive/2006/11/08/14875.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TOMCAT数据源配置</title><link>http://www.cppblog.com/jeromewen/archive/2006/11/08/14874.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Wed, 08 Nov 2006 12:18:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/11/08/14874.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/14874.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/11/08/14874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/14874.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/14874.html</trackback:ping><description><![CDATA[<p>网上这类文章特别多,此教程是本人实践确保一个正常运行的一个.<br />1.安装MYSQL TOMCAT<br />2.copy mysql-connector-java-3.1.11-bin.jar to %TOMCAT_HOME%\common\lib<br />drop database if exists datasource;<br />create database datasource;<br />use datasource;<br />create table user(<br />username varchar(50) not null,<br />password varchar(50),<br />primary key (username)<br />);<br />insert into user(username,password) values("kingbill","10041207");--插入测试数据<br />3.使用Tomcat的web管理应用配置数据源<br />3.1 <a href="http://127.0.0.1:8080/admin/">http://127.0.0.1:8080/admin/</a> enter username password<br />3.2 Resources-&gt;Data Sources-&gt;Data Source Actions-&gt;create New Data Source<br />3.3 JDBC Driver Class 不能随便添 Data Source URL可能是jdbc:mysql://IP:port<br />JNDI Name:MyDataSource<br />Data Source <a href="jdbc:mysql://127.0.0.1:3306/datasource">URL:jdbc:mysql://127.0.0.1:3306/datasource</a><br />JDBC Driver Class:org.gjt.mm.mysql.Driver<br />User Name:root<br />Password:123456<br />其余默认<br />Validation Query:可以不填<br />3.4 Save-&gt;Commit Change<br />4.在%TOMCAT_HOME%\conf\catalina\localhost\testapp.xml加入<br />添加&lt;ResourceLink global="MyDataSource" name="MyDataSource" type="javax.sql.DataSource"/&gt;<br />如果发布是%TOMCAT_HOME%\conf\server.xml配置则在&lt;context&gt; ... &lt;/context&gt; 里面加入<br />----------------------------按照如上步骤不会出现以下错误<br />Cannot create JDBC driver of class '' for connect URL 'null'<br />Name MyDataSource is not bound in this Context<br />Cannot load JDBC driver class 'org.git.mm.mysql.Driver'<br />---------------------------------------------------<br />测试代码Test.jsp<br />&lt;%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %&gt;<br />&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>"&gt;<br />&lt;<a href="mailto:%@page">%@page</a> import="javax.sql.*" %&gt;<br />&lt;<a href="mailto:%@page">%@page</a> import="javax.naming.*" %&gt;<br />&lt;<a href="mailto:%@page">%@page</a> session="false"%&gt;</p>
		<p>&lt;html&gt;<br />&lt;head&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312" /&gt;<br />&lt;title&gt;&lt;/title&gt;<br />&lt;%<br />DataSource ds=null;<br />Connection conn=null;<br />Statement stmt=null;<br />try{<br />InitialContext ctx=new InitialContext();<br />ds=(DataSource)ctx.lookup("java:comp/env/MyDataSource");<br />conn = ds.getConnection();<br />stmt = conn.createStatement();<br />String strSql="select * from user";<br />ResultSet rs=stmt.executeQuery(strSql);<br />while(rs.next()){<br /> out.println("用户名为 : " + rs.getString(1));<br /> }<br /> if(rs!=null) {rs.close();};<br /> if(stmt!=null) {stmt.close();};<br /> if(conn!=null) {conn.close();};<br />}<br />catch (SQLException e) {</p>
		<p>     // display SQL specific exception information <br />     System.out.println("*************************" );<br />     System.out.println("SQLException in main: " + e.getMessage() );<br />     System.out.println("** SQLState: " + e.getSQLState());<br />     System.out.println("** SQL Error Code: " + e.getErrorCode());<br />     System.out.println("*************************" );<br />     e.printStackTrace();<br />}<br />catch (Exception e) {<br />     System.out.println("Exception in main: " + e.getMessage() );<br />     e.printStackTrace();<br />}<br />%&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p>
		<p> </p><img src ="http://www.cppblog.com/jeromewen/aggbug/14874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-11-08 20:18 <a href="http://www.cppblog.com/jeromewen/archive/2006/11/08/14874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Playing with ptrace, Part II</title><link>http://www.cppblog.com/jeromewen/archive/2006/10/10/13516.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Tue, 10 Oct 2006 07:59:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/10/10/13516.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/13516.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/10/10/13516.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/13516.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/13516.html</trackback:ping><description><![CDATA[<h1 class="title">
				<span class="submitted">
						<font color="#999999" size="2">转自<a href="http://www.eecs.umich.edu/~ppadala">http://www.eecs.umich.edu/~ppadala</a></font>
				</span>
		</h1>
		<h1 class="title">
				<span class="submitted">
				</span>
				<span class="submitted">
						<font color="#999999" size="2">By </font>
						<a title="View user profile." href="http://www.linuxjournal.com/user/800841">
								<strong>
										<font color="#000000" size="2">Pradeep Padala</font>
								</strong>
						</a>
						<font color="#999999" size="2"> on Sun, 2002-12-01 02:00.</font>
				</span>
				<span class="taxonomy">
						<a href="http://www.linuxjournal.com/taxonomy/term/8">
								<strong>
										<font color="#000068" size="2">SysAdmin</font>
								</strong>
						</a>
				</span>
		</h1>
		<div class="node ">
				<div class="content">
						<p style="COLOR: red">
						</p>In Part II of his series on ptrace, Pradeep tackles the more advanced topics of setting breakpoints and injecting code into running processes. 
<div class="article" lang="en"><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x85739a4"></a></h2></div><p>In Part I of this article [<span class="emphasis"><em>LJ</em></span>, November 2002], we saw how ptrace can be used to trace system calls and change system call arguments. In this article, we investigate advanced techniques like setting breakpoints and injecting code into running programs. Debuggers use these methods to set up breakpoints and execute debugging handlers. As with Part I, all code in this article is i386 architecture-specific.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573a54"></a>Attaching to a Running Process</h2></div><p>In Part I, we ran the process to be traced as a child after calling ptrace(PTRACE_TRACEME, ..). If you simply wanted to see how the process is making system calls and trace the program, this would be sufficient. If you want to trace or debug a process already running, then ptrace(PTRACE_ATTACH, ..) should be used.</p><p>When a ptrace(PTRACE_ATTACH, ..) is called with the pid to be traced, it is roughly equivalent to the process calling ptrace(PTRACE_TRACEME, ..) and becoming a child of the tracing process. The traced process is sent a SIGSTOP, so we can examine and modify the process as usual. After we are done with modifications or tracing, we can let the traced process continue on its own by calling ptrace(PTRACE_DETACH, ..).</p><p>The following is the code for a small example tracing program:</p><pre class="programlisting"><tt>int main()
{   int i;
    for(i = 0;i &lt; 10; ++i) {
        printf("My counter: %d\n", i);
        sleep(2);
    }
    return 0;
}
</tt></pre><p>Save the program as dummy2.c. Compile and run it:</p><pre class="programlisting"><tt>gcc -o dummy2 dummy2.c
./dummy2 &amp;
</tt></pre>Now, we can attach to dummy2 by using the code below: <pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;   /* For user_regs_struct 
                             etc. */
int main(int argc, char *argv[])
{   pid_t traced_process;
    struct user_regs_struct regs;
    long ins;
    if(argc != 2) {
        printf("Usage: %s &lt;pid to be traced&gt;\n",
               argv[0], argv[1]);
        exit(1);
    }
    traced_process = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, traced_process, 
           NULL, NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS, traced_process, 
           NULL, &amp;regs);
    ins = ptrace(PTRACE_PEEKTEXT, traced_process, 
                 regs.eip, NULL);
    printf("EIP: %lx Instruction executed: %lx\n", 
           regs.eip, ins);
    ptrace(PTRACE_DETACH, traced_process, 
           NULL, NULL);
    return 0;
}
</tt></pre>The above program simply attaches to a process, waits for it to stop, examines its eip (instruction pointer) and detaches. <br /><br /><p>To inject code use ptrace(PTRACE_POKETEXT, ..) and ptrace(PTRACE_POKEDATA, ..) after the traced process has stopped.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573c0c"></a>Setting Breakpoints</h2></div><p>How do debuggers set breakpoints? Generally, they replace the instruction to be executed with a trap instruction, so that when the traced program stops, the tracing program, the debugger, can examine it. It will replace the original instruction once the tracing program continues the traced process. Here's an example:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;
const int long_size = sizeof(long);
void getdata(pid_t child, long addr, 
             char *str, int len)
{   char *laddr;
    int i, j;
    union u {
            long val;
            char chars[long_size];
    }data;
    i = 0;
    j = len / long_size;
    laddr = str;
    while(i &lt; j) {
        data.val = ptrace(PTRACE_PEEKDATA, child, 
                          addr + i * 4, NULL);
        memcpy(laddr, data.chars, long_size);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        data.val = ptrace(PTRACE_PEEKDATA, child, 
                          addr + i * 4, NULL);
        memcpy(laddr, data.chars, j);
    }
    str[len] = '\0';
}
void putdata(pid_t child, long addr, 
             char *str, int len)
{   char *laddr;
    int i, j;
    union u {
            long val;
            char chars[long_size];
    }data;
    i = 0;
    j = len / long_size;
    laddr = str;
    while(i &lt; j) {
        memcpy(data.chars, laddr, long_size);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        memcpy(data.chars, laddr, j);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
    }
}
int main(int argc, char *argv[])
{   pid_t traced_process;
    struct user_regs_struct regs, newregs;
    long ins;
    /* int 0x80, int3 */
    char code[] = {0xcd,0x80,0xcc,0};
    char backup[4];
    if(argc != 2) {
        printf("Usage: %s &lt;pid to be traced&gt;\n", 
               argv[0], argv[1]);
        exit(1);
    }
    traced_process = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, traced_process, 
           NULL, NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS, traced_process, 
           NULL, &amp;regs);
    /* Copy instructions into a backup variable */
    getdata(traced_process, regs.eip, backup, 3);
    /* Put the breakpoint */
    putdata(traced_process, regs.eip, code, 3);
    /* Let the process continue and execute 
       the int 3 instruction */
    ptrace(PTRACE_CONT, traced_process, NULL, NULL);
    wait(NULL);
    printf("The process stopped, putting back "
           "the original instructions\n");
    printf("Press &lt;enter&gt; to continue\n");
    getchar();
    putdata(traced_process, regs.eip, backup, 3);
    /* Setting the eip back to the original 
       instruction to let the process continue */
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &amp;regs);
    ptrace(PTRACE_DETACH, traced_process, 
           NULL, NULL);
    return 0;
}
</tt></pre><p>Here we replace the three bytes with the code for a trap instruction, and when the process stops, we replace the original instructions and reset the eip to original location. Figures 1-4 clarify how the instruction stream looks when above program is executed.<br /><br /></p><p>Now that we have a clear idea of how breakpoints are set, let's inject some code bytes into a running program. These code bytes will print ``hello world''.</p><p>The following program is a simple ``hello world'' program with modifications to fit our needs. Compile the following program with:</p><pre class="programlisting"><tt>gcc -o hello hello.c
void main()
{
__asm__("
         jmp forward
backward:
         popl   %esi      # Get the address of 
                          # hello world string
         movl   $4, %eax  # Do write system call
         movl   $2, %ebx
         movl   %esi, %ecx
         movl   $12, %edx
         int    $0x80
         int3             # Breakpoint. Here the 
                          # program will stop and 
                          # give control back to 
                          # the parent
forward:
         call   backward
         .string \"Hello World\\n\""
       );
}
</tt></pre><p>The jumping backward and forward here is required to find the address of the ``hello world'' string.</p><p>We can get the machine code for the above assembly from GDB. Fire up GDB and disassemble the program:</p><pre class="programlisting"><tt>(gdb) disassemble main
Dump of assembler code for function main:
0x80483e0 &lt;main&gt;:       push   %ebp
0x80483e1 &lt;main+1&gt;:     mov    %esp,%ebp
0x80483e3 &lt;main+3&gt;:     jmp    0x80483fa &lt;forward&gt;
End of assembler dump.
(gdb) disassemble forward
Dump of assembler code for function forward:
0x80483fa &lt;forward&gt;:    call   0x80483e5 &lt;backward&gt;
0x80483ff &lt;forward+5&gt;:  dec    %eax
0x8048400 &lt;forward+6&gt;:  gs
0x8048401 &lt;forward+7&gt;:  insb   (%dx),%es:(%edi)
0x8048402 &lt;forward+8&gt;:  insb   (%dx),%es:(%edi)
0x8048403 &lt;forward+9&gt;:  outsl  %ds:(%esi),(%dx)
0x8048404 &lt;forward+10&gt;: and    %dl,0x6f(%edi)
0x8048407 &lt;forward+13&gt;: jb     0x8048475
0x8048409 &lt;forward+15&gt;: or     %fs:(%eax),%al
0x804840c &lt;forward+18&gt;: mov    %ebp,%esp
0x804840e &lt;forward+20&gt;: pop    %ebp
0x804840f &lt;forward+21&gt;: ret
End of assembler dump.
(gdb) disassemble backward
Dump of assembler code for function backward:
0x80483e5 &lt;backward&gt;:   pop    %esi
0x80483e6 &lt;backward+1&gt;: mov    $0x4,%eax
0x80483eb &lt;backward+6&gt;: mov    $0x2,%ebx
0x80483f0 &lt;backward+11&gt;:        mov    %esi,%ecx
0x80483f2 &lt;backward+13&gt;:        mov    $0xc,%edx
0x80483f7 &lt;backward+18&gt;:        int    $0x80
0x80483f9 &lt;backward+20&gt;:        int3
End of assembler dump.
</tt></pre><p>We need to take the machine code bytes from main+3 to backward+20, which is a total of 41 bytes. The machine code can be seen with the x command in GDB:</p><pre class="programlisting"><tt>(gdb) x/40bx main+3
&lt;main+3&gt;: eb 15 5e b8 04 00 00 00
&lt;backward+6&gt;: bb 02 00 00 00 89 f1 ba
&lt;backward+14&gt;: 0c 00 00 00 cd 80 cc
&lt;forward+1&gt;: e6 ff ff ff 48 65 6c 6c
&lt;forward+9&gt;: 6f 20 57 6f 72 6c 64 0a
</tt></pre><p>Now we have the instruction bytes to be executed. Why wait? We can inject them using the same method as in the previous example. The following is the source code; only the main function is given here: </p><pre class="programlisting"><tt>int main(int argc, char *argv[])
{   pid_t traced_process;
    struct user_regs_struct regs, newregs;
    long ins;
    int len = 41;
    char insertcode[] =
"\xeb\x15\x5e\xb8\x04\x00"
        "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
        "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
        "\x72\x6c\x64\x0a\x00";
    char backup[len];
    if(argc != 2) {
        printf("Usage: %s &lt;pid to be traced&gt;\n", 
               argv[0], argv[1]);
        exit(1);
    }
    traced_process = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, traced_process, 
           NULL, NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS, traced_process, 
           NULL, &amp;regs);
    getdata(traced_process, regs.eip, backup, len);
    putdata(traced_process, regs.eip, 
            insertcode, len);
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &amp;regs);
    ptrace(PTRACE_CONT, traced_process, 
           NULL, NULL);
    wait(NULL);
    printf("The process stopped, Putting back "
           "the original instructions\n");
    putdata(traced_process, regs.eip, backup, len);
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &amp;regs);
    printf("Letting it continue with "
           "original flow\n");
    ptrace(PTRACE_DETACH, traced_process,
           NULL, NULL);
    return 0;
}
</tt></pre><p><br /><br /></p><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x85744a4"></a>Injecting the Code into Free Space</h2></div><p>In the previous example we injected the code directly into the executing instruction stream. However, debuggers can get confused with this kind of behaviour, so let's find the free space in the process and inject the code there. We can find free space by examining the /proc/pid/maps file of the traced process. The following function will find the starting address of this map:</p><pre class="programlisting"><tt>long freespaceaddr(pid_t pid)
{
    FILE *fp;
    char filename[30];
    char line[85];
    long addr;
    char str[20];
    sprintf(filename, "/proc/%d/maps", pid);
    fp = fopen(filename, "r");
    if(fp == NULL)
        exit(1);
    while(fgets(line, 85, fp) != NULL) {
        sscanf(line, "%lx-%*lx %*s %*s %s", &amp;addr, 
               str, str, str, str);
        if(strcmp(str, "00:00") == 0)
            break;
    }
    fclose(fp);
    return addr;
}
</tt></pre><p>Each line in /proc/pid/maps represents a mapped region of the process. An entry in /proc/pid/maps looks like this:</p><pre class="programlisting"><tt>map start-mapend    protection  offset     device   
inode      process file
08048000-0804d000   r-xp        00000000   03:08    
66111      /opt/kde2/bin/kdeinit
</tt></pre>The following program injects code into free space. It's similar to the previous injection program except the free space address is used for keeping our new code. Here is the source code for the main function: <pre class="programlisting"><tt>int main(int argc, char *argv[])
{   pid_t traced_process;
    struct user_regs_struct oldregs, regs;
    long ins;
    int len = 41;
    char insertcode[] =
"\xeb\x15\x5e\xb8\x04\x00"
        "\x00\x00\xbb\x02\x00\x00\x00\x89\xf1\xba"
        "\x0c\x00\x00\x00\xcd\x80\xcc\xe8\xe6\xff"
        "\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f"
        "\x72\x6c\x64\x0a\x00";
    char backup[len];
    long addr;
    if(argc != 2) {
        printf("Usage: %s &lt;pid to be traced&gt;\n", 
               argv[0], argv[1]);
        exit(1);
    }
    traced_process = atoi(argv[1]);
    ptrace(PTRACE_ATTACH, traced_process, 
           NULL, NULL);
    wait(NULL);
    ptrace(PTRACE_GETREGS, traced_process, 
           NULL, &amp;regs);
    addr = freespaceaddr(traced_process);
    getdata(traced_process, addr, backup, len);
    putdata(traced_process, addr, insertcode, len);
    memcpy(&amp;oldregs, &amp;regs, sizeof(regs));
    regs.eip = addr;
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &amp;regs);
    ptrace(PTRACE_CONT, traced_process, 
           NULL, NULL);
    wait(NULL);
    printf("The process stopped, Putting back "
           "the original instructions\n");
    putdata(traced_process, addr, backup, len);
    ptrace(PTRACE_SETREGS, traced_process, 
           NULL, &amp;oldregs);
    printf("Letting it continue with "
           "original flow\n");
    ptrace(PTRACE_DETACH, traced_process, 
           NULL, NULL);
    return 0;
}
</tt></pre><br /><br /></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x85745d8"></a>Behind the Scenes</h2></div><p>So what happens within the kernel now? How is ptrace implemented? This section could be an article on its own; however, here's a brief description of what happens.</p><p>When a process calls ptrace with PTRACE_TRACEME, the kernel sets up the process flags to reflect that it is being traced:</p><pre class="programlisting"><tt>Source: arch/i386/kernel/ptrace.c
if (request == PTRACE_TRACEME) {
    /* are we already being traced? */
    if (current-&gt;ptrace &amp; PT_PTRACED)
        goto out;
    /* set the ptrace bit in the process flags. */
    current-&gt;ptrace |= PT_PTRACED;
    ret = 0;
    goto out;
}
</tt></pre><p>When a system call entry is done, the kernel checks this flag and calls the trace system call if the process is being traced. The gory assembly details can be found in arch/i386/kernel/entry.S.</p><p>Now, we are in the sys_trace() function as defined in arch/i386/kernel/ptrace.c. It stops the child and sends a signal to the parent notifying that the child is stopped. This wakes up the waiting parent, and it does the ptrace magic. Once the parent is done, and it calls ptrace(PTRACE_CONT, ..) or ptrace(PTRACE_SYSCALL, ..), it wakes up the child by calling the scheduler function wake_up_process(). Some other architectures can implement this by sending a SIGCHLD to child.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x87979cc"></a>Conclusion</h2></div><p><span class="bold"><b>ptrace</b></span> may appear to be magic to some people, because it can examine and modify a running program. It is generally used by debuggers and system call tracing programs, such as ptrace. It opens up interesting possibilities for doing user-mode extensions as well. There have been a lot of attempts to extend the operating system on the user level. See Resources to read about UFO, a user-level extension to filesystems. <span class="bold"><b>ptrace</b></span> also is used to employ security mechanisms.</p><p>All example code from this article and from Part I is available as a tar archive on the <span class="emphasis"><em>Linux Journal</em></span> FTP site [<a href="ftp://ftp.ssc.com/pub/lj/listings/issue104/6210.tgz" target="_top"><strong><font color="#000000">ftp.ssc.com/pub/lj/listings/issue104/6210.tgz</font></strong></a>].<br /></p></div></div></div></div>
		</div><img src ="http://www.cppblog.com/jeromewen/aggbug/13516.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-10-10 15:59 <a href="http://www.cppblog.com/jeromewen/archive/2006/10/10/13516.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Playing with ptrace, Part I</title><link>http://www.cppblog.com/jeromewen/archive/2006/10/10/13514.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Tue, 10 Oct 2006 06:48:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/10/10/13514.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/13514.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/10/10/13514.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/13514.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/13514.html</trackback:ping><description><![CDATA[<p>来自<a href="http://www.linuxjournal.com/article/6100">http://www.linuxjournal.com/article/6100</a><br /><span class="submitted">By <a title="View user profile." href="http://www.linuxjournal.com/user/800841">Pradeep Padala</a> on Fri, 2002-11-01 02:00.</span><span class="taxonomy"><a href="http://www.linuxjournal.com/taxonomy/term/8">SysAdmin</a></span></p>
		<div class="content">
				<p style="COLOR: red">
				</p>Using ptrace allows you to set up system call interception and modification at the user level. 
<div class="article" lang="en"><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573aac"></a></h2></div><p>Have you ever wondered how system calls can be intercepted? Have you ever tried fooling the kernel by changing system call arguments? Have you ever wondered how debuggers stop a running process and let you take control of the process?</p><p>If you are thinking of using complex kernel programming to accomplish tasks, think again. Linux provides an elegant mechanism to achieve all of these things: the ptrace (Process Trace) system call. <span class="bold"><b>ptrace</b></span> provides a mechanism by which a parent process may observe and control the execution of another process. It can examine and change its core image and registers and is used primarily to implement breakpoint debugging and system call tracing.</p><p>In this article, we learn how to intercept a system call and change its arguments. In Part II of the article we will study advanced techniques--setting breakpoints and injecting code into a running program. We will peek into the child process' registers and data segment and modify the contents. We will also describe a way to inject code so the process can be stopped and execute arbitrary instructions.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573bb4"></a>Basics</h2></div><p>Operating systems offer services through a standard mechanism called system calls. They provide a standard API for accessing the underlying hardware and low-level services, such as the filesystems. When a process wants to invoke a system call, it puts the arguments to system calls in registers and calls soft interrupt 0x80. This soft interrupt is like a gate to the kernel mode, and the kernel will execute the system call after examining the arguments.</p><p>On the i386 architecture (all the code in this article is i386-specific), the system call number is put in the register %eax. The arguments to this system call are put into registers %ebx, %ecx, %edx, %esi and %edi, in that order. For example, the call:</p><pre class="programlisting"><tt>write(2, "Hello", 5)
</tt></pre><p>roughly would translate into</p><pre class="programlisting"><tt>movl   $4, %eax
movl   $2, %ebx
movl   $hello,%ecx
movl   $5, %edx
int    $0x80
</tt></pre>where $hello points to a literal string "Hello". <br /><br /><p>So where does ptrace come into picture? Before executing the system call, the kernel checks whether the process is being traced. If it is, the kernel stops the process and gives control to the tracking process so it can examine and modify the traced process' registers.</p><p>Let's clarify this explanation with an example of how the process works:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;   /* For constants 
                                   ORIG_EAX etc */
int main()
{   pid_t child;
    long orig_eax;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
        wait(NULL);
        orig_eax = ptrace(PTRACE_PEEKUSER, 
                          child, 4 * ORIG_EAX, 
                          NULL);
        printf("The child made a "
               "system call %ld\n", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}
</tt></pre><p>When run, this program prints:</p><pre class="programlisting"><tt>The child made a system call 11
</tt></pre>along with the output of ls. System call number 11 is execve, and it's the first system call executed by the child. For reference, system call numbers can be found in /usr/include/asm/unistd.h. <br /><br /><p>As you can see in the example, a process forks a child and the child executes the process we want to trace. Before running <b>exec</b>, the child calls ptrace with the first argument, equal to PTRACE_TRACEME. This tells the kernel that the process is being traced, and when the child executes the execve system call, it hands over control to its parent. The parent waits for notification from the kernel with a wait() call. Then the parent can check the arguments of the system call or do other things, such as looking into the registers.</p><p>When the system call occurs, the kernel saves the original contents of the eax register, which contains the system call number. We can read this value from child's USER segment by calling ptrace with the first argument PTRACE_PEEKUSER, shown as above.</p><p>After we are done examining the system call, the child can continue with a call to ptrace with the first argument PTRACE_CONT, which lets the system call continue.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573e74"></a>ptrace Parameters</h2></div><p><span class="bold"><b>ptrace</b></span> is called with four arguments:</p><pre class="programlisting"><tt>long ptrace(enum __ptrace_request request,
            pid_t pid,
            void *addr,
            void *data);
</tt></pre><p>The first argument determines the behaviour of ptrace and how other arguments are used. The value of request should be one of PTRACE_TRACEME, PTRACE_PEEKTEXT, PTRACE_PEEKDATA, PTRACE_PEEKUSER, PTRACE_POKETEXT, PTRACE_POKEDATA, PTRACE_POKEUSER, PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_SETREGS, PTRACE_SETFPREGS, PTRACE_CONT, PTRACE_SYSCALL, PTRACE_SINGLESTEP, PTRACE_DETACH. The significance of each of these requests will be explained in the rest of the article.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8573f7c"></a>Reading System Call Parameters</h2></div><p>By calling ptrace with PTRACE_PEEKUSER as the first argument, we can examine the contents of the USER area where register contents and other information is stored. The kernel stores the contents of registers in this area for the parent process to examine through ptrace.</p><p>Let's show this with an example:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;
#include &lt;sys/syscall.h&gt;   /* For SYS_write etc */
int main()
{   pid_t child;
    long orig_eax, eax;
    long params[3];
    int status;
    int insyscall = 0;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
       while(1) {
          wait(&amp;status);
          if(WIFEXITED(status))
              break;
          orig_eax = ptrace(PTRACE_PEEKUSER, 
                     child, 4 * ORIG_EAX, NULL);
          if(orig_eax == SYS_write) {
             if(insyscall == 0) {    
                /* Syscall entry */
                insyscall = 1;
                params[0] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * EBX, 
                                   NULL);
                params[1] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * ECX, 
                                   NULL);
                params[2] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * EDX, 
                                   NULL);
                printf("Write called with "
                       "%ld, %ld, %ld\n",
                       params[0], params[1],
                       params[2]);
                }
          else { /* Syscall exit */
                eax = ptrace(PTRACE_PEEKUSER, 
                             child, 4 * EAX, NULL);
                    printf("Write returned "
                           "with %ld\n", eax);
                    insyscall = 0;
                }
            }
            ptrace(PTRACE_SYSCALL, 
                   child, NULL, NULL);
        }
    }
    return 0;
}
</tt></pre><p>This program should print an output similar to the following:</p><pre class="programlisting"><tt>ppadala@linux:~/ptrace &gt; ls
a.out        dummy.s      ptrace.txt   
libgpm.html  registers.c  syscallparams.c
dummy        ptrace.html  simple.c
ppadala@linux:~/ptrace &gt; ./a.out
Write called with 1, 1075154944, 48
a.out        dummy.s      ptrace.txt
Write returned with 48
Write called with 1, 1075154944, 59
libgpm.html  registers.c  syscallparams.c
Write returned with 59
Write called with 1, 1075154944, 30
dummy        ptrace.html  simple.c
Write returned with 30
</tt></pre>Here we are tracing the write system calls, and <b>ls</b> makes three write system calls. The call to ptrace, with a first argument of PTRACE_SYSCALL, makes the kernel stop the child process whenever a system call entry or exit is made. It's equivalent to doing a PTRACE_CONT and stopping at the next system call entry/exit. <br /><br /><p>In the previous example, we used PTRACE_PEEKUSER to look into the arguments of the write system call. When a system call returns, the return value is placed in %eax, and it can be read as shown in that example.</p><p>The status variable in the wait call is used to check whether the child has exited. This is the typical way to check whether the child has been stopped by ptrace or was able to exit. For more details on macros like WIFEXITED, see the wait(2) man page.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8574134"></a>Reading Register Values</h2></div><p>If you want to read register values at the time of a syscall entry or exit, the procedure shown above can be cumbersome. Calling ptrace with a first argument of PTRACE_GETREGS will place all the registers in a single call.</p><p>The code to fetch register values looks like this:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;
#include &lt;sys/syscall.h&gt;
int main()
{   pid_t child;
    long orig_eax, eax;
    long params[3];
    int status;
    int insyscall = 0;
    struct user_regs_struct regs;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else {
       while(1) {
          wait(&amp;status);
          if(WIFEXITED(status))
              break;
          orig_eax = ptrace(PTRACE_PEEKUSER, 
                            child, 4 * ORIG_EAX, 
                            NULL);
          if(orig_eax == SYS_write) {
              if(insyscall == 0) {
                 /* Syscall entry */
                 insyscall = 1;
                 ptrace(PTRACE_GETREGS, child, 
                        NULL, &amp;regs);
                 printf("Write called with "
                        "%ld, %ld, %ld\n",
                        regs.ebx, regs.ecx, 
                        regs.edx);
             }
             else { /* Syscall exit */
                 eax = ptrace(PTRACE_PEEKUSER, 
                              child, 4 * EAX, 
                              NULL);
                 printf("Write returned "
                        "with %ld\n", eax);
                 insyscall = 0;
             }
          }
          ptrace(PTRACE_SYSCALL, child,
                 NULL, NULL);
       }
   }
   return 0;
}
</tt></pre><p>This code is similar to the previous example except for the call to ptrace with PTRACE_GETREGS. Here we have made use of the user_regs_struct defined in &lt;linux/user.h&gt; to read the register values.</p></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x857423c"></a>Doing Funny Things</h2></div><p>Now it's time for some fun. In the following example, we will reverse the string passed to the write system call:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt;
#include &lt;sys/syscall.h&gt;
const int long_size = sizeof(long);
void reverse(char *str)
{   int i, j;
    char temp;
    for(i = 0, j = strlen(str) - 2; 
        i &lt;= j; ++i, --j) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
    }
}
void getdata(pid_t child, long addr, 
             char *str, int len)
{   char *laddr;
    int i, j;
    union u {
            long val;
            char chars[long_size];
    }data;
    i = 0;
    j = len / long_size;
    laddr = str;
    while(i &lt; j) {
        data.val = ptrace(PTRACE_PEEKDATA, 
                          child, addr + i * 4, 
                          NULL);
        memcpy(laddr, data.chars, long_size);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        data.val = ptrace(PTRACE_PEEKDATA, 
                          child, addr + i * 4, 
                          NULL);
        memcpy(laddr, data.chars, j);
    }
    str[len] = '\0';
}
void putdata(pid_t child, long addr, 
             char *str, int len)
{   char *laddr;
    int i, j;
    union u {
            long val;
            char chars[long_size];
    }data;
    i = 0;
    j = len / long_size;
    laddr = str;
    while(i &lt; j) {
        memcpy(data.chars, laddr, long_size);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) {
        memcpy(data.chars, laddr, j);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
    }
}
int main()
{   
   pid_t child;
   child = fork();
   if(child == 0) {
      ptrace(PTRACE_TRACEME, 0, NULL, NULL);
      execl("/bin/ls", "ls", NULL);
   }
   else {
      long orig_eax;
      long params[3];
      int status;
      char *str, *laddr;
      int toggle = 0;
      while(1) {
         wait(&amp;status);
         if(WIFEXITED(status))
             break;
         orig_eax = ptrace(PTRACE_PEEKUSER, 
                           child, 4 * ORIG_EAX, 
                           NULL);
         if(orig_eax == SYS_write) {
            if(toggle == 0) {
               toggle = 1;
               params[0] = ptrace(PTRACE_PEEKUSER, 
                                  child, 4 * EBX, 
                                  NULL);
               params[1] = ptrace(PTRACE_PEEKUSER, 
                                  child, 4 * ECX, 
                                  NULL);
               params[2] = ptrace(PTRACE_PEEKUSER,
                                  child, 4 * EDX, 
                                  NULL);
               str = (char *)calloc((params[2]+1)
                                 * sizeof(char));
               getdata(child, params[1], str, 
                       params[2]);
               reverse(str);
               putdata(child, params[1], str, 
                       params[2]);
            }
            else {
               toggle = 0;
            }
         }
      ptrace(PTRACE_SYSCALL, child, NULL, NULL);
      }
   }
   return 0;
}
</tt></pre><p>The output looks like this:</p><pre class="programlisting"><tt>ppadala@linux:~/ptrace &gt; ls
a.out        dummy.s      ptrace.txt
libgpm.html  registers.c  syscallparams.c
dummy        ptrace.html  simple.c
ppadala@linux:~/ptrace &gt; ./a.out
txt.ecartp      s.ymmud      tuo.a
c.sretsiger     lmth.mpgbil  c.llacys_egnahc
c.elpmis        lmth.ecartp  ymmud
</tt></pre>This example makes use of all the concepts previously discussed, plus a few more. In it, we use calls to ptrace with PTRACE_POKEDATA to change the data values. It works exactly the same way as PTRACE_PEEKDATA, except it both reads and writes the data thatt the child passes in arguments to the system call whereas PEEKDATA only reads the data. <br /><br /></div><div class="simplesect" lang="en"><div class="titlepage"><h2 class="title"><a name="N0x850ca10.0x8574344"></a>Single-Stepping</h2></div><p><span class="bold"><b>ptrace</b></span> provides features to single-step through the child's code. The call to ptrace(PTRACE_SINGLESTEP,..) tells the kernel to stop the child at each instruction and let the parent take control. The following example shows a way of reading the instruction being executed when a system call is executed. I have created a small dummy executable for you to understand what is happening instead of bothering with the calls made by libc.</p><p>Here's the listing for dummy1.s. It's written in assembly language and compiled as gcc -o dummy1 dummy1.s:</p><pre class="programlisting"><tt>.data
hello:
    .string "hello world\n"
.globl  main
main:
    movl    $4, %eax
    movl    $2, %ebx
    movl    $hello, %ecx
    movl    $12, %edx
    int     $0x80
    movl    $1, %eax
    xorl    %ebx, %ebx
    int     $0x80
    ret
</tt></pre><p>The example program that single-steps through the above code is:</p><pre class="programlisting"><tt>#include &lt;sys/ptrace.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include &lt;unistd.h&gt;
#include &lt;linux/user.h&gt; 
#include &lt;sys/syscall.h&gt;
int main()
{   pid_t child;
    const int long_size = sizeof(long);
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("./dummy1", "dummy1", NULL);
    }
    else {
        int status;
        union u {
            long val;
            char chars[long_size];
        }data;
        struct user_regs_struct regs;
        int start = 0;
        long ins;
        while(1) {
            wait(&amp;status);
            if(WIFEXITED(status))
                break;
            ptrace(PTRACE_GETREGS, 
                   child, NULL, &amp;regs);
            if(start == 1) {
                ins = ptrace(PTRACE_PEEKTEXT, 
                             child, regs.eip, 
                             NULL);
                printf("EIP: %lx Instruction "
                       "executed: %lx\n", 
                       regs.eip, ins);
            }
            if(regs.orig_eax == SYS_write) {
                start = 1;
                ptrace(PTRACE_SINGLESTEP, child, 
                       NULL, NULL);
            }
            else
                ptrace(PTRACE_SYSCALL, child, 
                       NULL, NULL);
        }
    }
    return 0;
}
</tt></pre>This program prints: <pre class="programlisting"><tt>hello world
EIP: 8049478 Instruction executed: 80cddb31
EIP: 804947c Instruction executed: c3
</tt></pre>You might have to look at Intel's manuals to make sense out of those instruction bytes. Using single stepping for more complex processes, such as setting breakpoints, requires careful design and more complex code. <br /><br /><p>In Part II, we will see how breakpoints can be inserted and code can be injected into a running program.</p></div></div></div><img src ="http://www.cppblog.com/jeromewen/aggbug/13514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-10-10 14:48 <a href="http://www.cppblog.com/jeromewen/archive/2006/10/10/13514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POP(110)监控</title><link>http://www.cppblog.com/jeromewen/archive/2006/09/29/13141.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Fri, 29 Sep 2006 05:07:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/09/29/13141.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/13141.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/09/29/13141.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/13141.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/13141.html</trackback:ping><description><![CDATA[<p>#include "nids.h"<br />#include &lt;cstdio&gt;<br />#pragma comment(lib,"ws2_32")<br />#pragma comment(lib,"wpcap")<br />#pragma comment(lib,"libnids")<br />char ascii_string[10000];<br />char * char_to_ascii(char ch)<br />{<br /> char * string;<br /> ascii_string[0] = 0;<br /> string = ascii_string;<br /> if(isgraph(ch))<br /> {<br />  *string++ =ch;<br /> }<br /> else if (ch == '\n' || ch == '\r')<br /> {<br />  *string++ =ch;<br /> }<br /> else<br /> {<br />  *string++ = '.';<br /> }<br /> *string  = 0;<br /> return ascii_string;<br />}</p>
		<p>void pop3_protocol_callback(struct tcp_stream* pop3_connection, void **arg)<br />{<br /> int i;<br /> char address_string[1024];<br /> char content[65535];<br /> char content_urgent[65535];<br /> struct tuple4 ip_and_port = pop3_connection-&gt;addr;<br /> strcpy(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.saddr))));<br /> sprintf(address_string+strlen(address_string),": %i",ip_and_port.source);<br /> strcat(address_string, " &lt;----&gt; ");<br /> strcat(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.daddr))));<br /> sprintf(address_string+strlen(address_string),": %i",ip_and_port.dest);<br /> strcat(address_string,"\n");<br /> switch (pop3_connection-&gt;nids_state)<br /> {<br /> case NIDS_JUST_EST:<br />  if(pop3_connection-&gt;addr.dest == 110)<br />  {<br />  pop3_connection-&gt;client.collect++;<br />  pop3_connection-&gt;client.collect_urg++;<br />  pop3_connection-&gt;server.collect++;<br />  pop3_connection-&gt;server.collect_urg++;<br />  printf("%sPOP3客户端和服务端建立连接\n", address_string);<br />  }<br />  return;<br /> case NIDS_CLOSE:<br />  printf("---------------------------------------\n");<br />  printf("%sPOP3客户端和服务端正常关闭\n", address_string);<br />  return;<br /> case NIDS_RESET:<br />  printf("---------------------------------------\n");<br />  printf("%sPOP3客户端和服务端被RST关闭\n", address_string);<br />  return;<br /> case NIDS_DATA:<br />  {<br />   char status_code[5];<br />   struct half_stream* hlf;<br />   if(pop3_connection-&gt;server.count_new_urg)<br />   {<br />    printf("----------------------------------------\n");<br />    strcpy(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.saddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.source);<br />    strcat(address_string, " urgent----&gt; ");<br />    strcat(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.daddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.dest);<br />    strcat(address_string,"\n");<br />    address_string[strlen(address_string)+1] = 0;<br />    address_string[strlen(address_string)] = pop3_connection-&gt;server.urgdata;<br />    printf("%s",address_string);<br />    return;<br />   }<br />   if (pop3_connection-&gt;client.count_new_urg)<br />   {<br />    printf("----------------------------------------\n");<br />    strcpy(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.saddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.source);<br />    strcat(address_string, " &lt;------urgent");<br />    strcat(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.daddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.dest);<br />    strcat(address_string,"\n");<br />    address_string[strlen(address_string)+1] = 0;<br />    address_string[strlen(address_string)] = pop3_connection-&gt;server.urgdata;<br />    printf("%s",address_string);<br />    return;<br />   }<br />   if (pop3_connection-&gt;client.count_new)<br />   {<br />    hlf = &amp;pop3_connection-&gt;client;<br />    strcpy(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.saddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.source);<br />    strcat(address_string, " &lt;-----");<br />    strcat(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.daddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.dest);<br />    strcat(address_string,"\n");<br />    printf("----------------------------------------\n");<br />    printf("%s",address_string);<br />    memcpy(content, hlf-&gt;data, hlf-&gt;count_new);<br />    content[hlf-&gt;count_new] = '\0';<br />    if (strstr(strncpy(status_code,content,4),"+OK")) <br />     printf("操作成功\n");<br />    if (strstr(strncpy(status_code,content,4),"-ERR")) <br />     printf("操作失败\n");<br />    for(i = 0;i&lt;hlf-&gt;count_new;i++)<br />    {<br />     printf("%s",char_to_ascii(content[i]));<br />    }<br />    printf("\n");<br />    if (strstr(content,"\n\r.\n\r"))<br />     printf("数据传输结束\n");<br />   }<br />   else<br />   {<br />    hlf = &amp;pop3_connection-&gt;server;<br />    strcpy(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.saddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.source);<br />    strcat(address_string, " &lt;-----");<br />    strcat(address_string, inet_ntoa(*((struct in_addr*)&amp;(ip_and_port.daddr))));<br />    sprintf(address_string+strlen(address_string),": %i",ip_and_port.dest);<br />    strcat(address_string,"\n");<br />    printf("----------------------------------------\n");<br />    printf("%s",address_string);<br />    memcpy(content, hlf-&gt;data, hlf-&gt;count_new);<br />    content[hlf-&gt;count_new] = '\0';<br />    if(strstr(content, "USER"))<br />     printf("邮件用户名为\n");<br />    if(strstr(content, "PASS"))<br />     printf("用户密码为\n");<br />    if(strstr(content, "STAT"))<br />     printf("返回统计资料\n");<br />    if(strstr(content, "LIST"))<br />     printf("返回邮件数量和大小\n");<br />    if(strstr(content, "RETR"))<br />     printf("获取邮件\n");<br />    if(strstr(content, "DELE"))<br />     printf("删除邮件\n");<br />    if(strstr(content, "QUIT"))<br />     printf("退出连接\n");</p>
		<p>    for(i = 0;i&lt;hlf-&gt;count_new;i++)<br />    {<br />     printf("%s",char_to_ascii(content[i]));<br />    }<br />    printf("\n");<br />   }<br />  }<br /> default:<br />  break;<br /> }<br /> return ;<br />}<br />int main(int argc, char **argv)<br />{<br /> if(!nids_init())<br /> {<br />  printf("出现错误: %s\n", nids_errbuf);<br />  exit(1);<br /> }</p>
		<p> nids_register_tcp(pop3_protocol_callback);<br /> nids_run();<br /> return 0;<br />}</p><img src ="http://www.cppblog.com/jeromewen/aggbug/13141.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-09-29 13:07 <a href="http://www.cppblog.com/jeromewen/archive/2006/09/29/13141.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Nids.h详细注释 </title><link>http://www.cppblog.com/jeromewen/archive/2006/09/29/13138.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Fri, 29 Sep 2006 04:31:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/09/29/13138.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/13138.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/09/29/13138.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/13138.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/13138.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: #ifndef _NIDS_NIDS_H								#define _NIDS_NIDS_H								#define NIDS_MAJOR 1     /*				主版本号				*/																												#define NIDS_MINOR 20    /*				次版本号				*/...&nbsp;&nbsp;<a href='http://www.cppblog.com/jeromewen/archive/2006/09/29/13138.html'>阅读全文</a><img src ="http://www.cppblog.com/jeromewen/aggbug/13138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-09-29 12:31 <a href="http://www.cppblog.com/jeromewen/archive/2006/09/29/13138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LIBNIDS编译错误解决方案 </title><link>http://www.cppblog.com/jeromewen/archive/2006/09/29/13137.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Fri, 29 Sep 2006 04:30:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/09/29/13137.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/13137.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/09/29/13137.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/13137.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/13137.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 新宋体">
						<span style="mso-list: Ignore">1.<span style="FONT: 7pt 'Times New Roman'"><font size="3">       </font></span></span>
				</span>
				<span lang="EN-US" style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">error LNK2019: </span>
				<span style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">无法解析的外部符号<span lang="EN-US"> _inet_ntoa@4 </span>，该符号在函数<span lang="EN-US"> _adres </span>中被引用<span lang="EN-US"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">需要加入</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">ws2_32.lib</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 新宋体">
						<span style="mso-list: Ignore">2.<span style="FONT: 7pt 'Times New Roman'"><font size="3">       </font></span></span>
				</span>
				<span lang="EN-US" style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">error LNK2019: </span>
				<span style="FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">无法解析的外部符号<span lang="EN-US"> "int __cdecl nids_init(void)" (?nids_init@@YAHXZ) </span>，该符号在函数<span lang="EN-US"> _main </span>中被引用<span lang="EN-US"><o:p></o:p></span></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">改写</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">nids.h<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">在函数前加入</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">#ifdef __cplusplus<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">extern "C"<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">#endif<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">在函数后加入</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">#ifdef __cplusplus<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">#endif</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">3.<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">libnids.lib(libnids.obj) : error LNK2019: </span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">无法解析的外部符号</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">_pcap_datalink </span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">，该符号在函数</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">_nids_init </span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">中被引用。。。。。。。。。。。。</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">需要加入</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">wpcap.lib<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">4.<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">LIBCMT.lib(close.obj) : error LNK2005: __close </span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">已经在</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">LIBCD.lib(close.obj) </span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">中定义。。。。。。。。。</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">解决方案属性</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">-</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">〉链接器</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">-</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">〉输入</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">-</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">〉忽略指定库</span>
				<span style="mso-bidi-font-size: 10.5pt">
						<span lang="EN-US">LIBCMT.lib</span>
				</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">而不是</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">LIBCD.lib<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-ALIGN: left" align="left">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">Libcd.lib</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">为</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">DEBUG</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">版本</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">libc.lib</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">为</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">Release</span>
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">版本得</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt; mso-layout-grid-align: none" align="left">
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 新宋体">
								<span style="mso-list: Ignore">5.<span style="FONT: 7pt 'Times New Roman'">        </span></span>
						</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">error LNK2019: </span>
						<span style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">无法解析的外部符号<span lang="EN-US"> _nids_run </span>，该符号在函数<span lang="EN-US"> _main </span>中被引用<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 新宋体; mso-bidi-font-size: 10.5pt; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">需要加入</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">libnids.lib<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="COLOR: black; mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">6.<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">error LNK2001: </span>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">无法解析的外部符号<span lang="EN-US"> "char * nids_errbuf" (?nids_errbuf@@3PADA)</span></span>
						<span lang="EN-US" style="COLOR: black; mso-bidi-font-size: 10.5pt">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">仅出现此错误的时候参考一下内容</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt">
				<span lang="EN-US" style="COLOR: blue">C</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">＋＋</span>
				<span style="COLOR: blue">
				</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">的全局常量只有静态连接性能。这不同于</span>
				<span lang="EN-US" style="COLOR: blue">C</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">，如果试图在</span>
				<span lang="EN-US" style="COLOR: blue">C</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">＋＋的多个文件内使用全局变量也会产生</span>
				<span lang="EN-US" style="COLOR: blue">LNK2001</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">错误。</span>
				<span lang="EN-US" style="COLOR: blue">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo4; tab-stops: list 42.0pt">
				<span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Wingdings; mso-bidi-font-family: Wingdings; mso-fareast-font-family: Wingdings">
						<span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">一种解决的方法是需要时在头文件中加入该常量的初始化代码，并在</span>
				<span lang="EN-US" style="COLOR: blue">.CPP</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">文件中包含该头文件；</span>
				<span lang="EN-US" style="COLOR: blue">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo4; tab-stops: list 42.0pt">
				<span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Wingdings; mso-bidi-font-family: Wingdings; mso-fareast-font-family: Wingdings">
						<span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">另一种方法是使用时给该变量赋以常数。</span>
				<span lang="EN-US" style="COLOR: blue">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="COLOR: blue; FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">改写</span>
				<span lang="EN-US" style="COLOR: blue; mso-bidi-font-size: 10.5pt">nids.h<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">extern char nids_errbuf[]="";<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-list: l1 level1 lfo1; tab-stops: list 21.0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt; mso-fareast-font-family: 'Times New Roman'">
						<span style="mso-list: Ignore">7.<span style="FONT: 7pt 'Times New Roman'"><font size="3">         </font></span></span>
				</span>
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">error LNK2001: </span>
						<span style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">无法解析的外部符号<span lang="EN-US"> "struct nids_prm nids_params" (?nids_params@@3Unids_prm@@A)</span></span>
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
								<o:p>
								</o:p>
						</span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">需要在源码文件中加入</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
						<font size="3">struct nids_prm nids_params;<o:p></o:p></font>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p> </o:p>
				</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">总结如下</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">:<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'">在代码中加入</span>
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">#pragma</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
								<span style="COLOR: blue">comment</span>(<span style="COLOR: blue">lib</span>,"</span>
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">ws2_32</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">")<o:p></o:p></span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">#pragma</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
								<span style="COLOR: blue">comment</span>(<span style="COLOR: blue">lib</span>,"</span>
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">libnids</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">")<o:p></o:p></span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<font size="3">
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">#pragma</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
								<span style="COLOR: blue">comment</span>(<span style="COLOR: blue">lib</span>,"</span>
						<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">wpcap</span>
						<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">")<o:p></o:p></span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
						<o:p>
								<font size="3"> </font>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
						<font size="3">属性<span lang="EN-US">-&gt;</span>连接器<span lang="EN-US">-&gt;</span>命令行<span lang="EN-US"><o:p></o:p></span></font>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'">
						<font size="3">加入<span lang="EN-US"><o:p></o:p></span></font>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US" style="mso-bidi-font-size: 10.5pt">ws2_32.lib libnids.lib wpcap.lib /verbose:lib /NODEFAULTLIB:libcpd.lib /NODEFAULTLIB:LIBCMT.lib<o:p></o:p></span>
		</p><img src ="http://www.cppblog.com/jeromewen/aggbug/13137.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-09-29 12:30 <a href="http://www.cppblog.com/jeromewen/archive/2006/09/29/13137.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gmake下载地址</title><link>http://www.cppblog.com/jeromewen/archive/2006/09/18/12679.html</link><dc:creator>JeromeWen</dc:creator><author>JeromeWen</author><pubDate>Mon, 18 Sep 2006 05:51:00 GMT</pubDate><guid>http://www.cppblog.com/jeromewen/archive/2006/09/18/12679.html</guid><wfw:comment>http://www.cppblog.com/jeromewen/comments/12679.html</wfw:comment><comments>http://www.cppblog.com/jeromewen/archive/2006/09/18/12679.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/jeromewen/comments/commentRss/12679.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jeromewen/services/trackbacks/12679.html</trackback:ping><description><![CDATA[
		<p>
				<a href="ftp://ftp.gnu.org/pub/gnu/make/make-3.80.tar.gz">ftp://ftp.gnu.org/pub/gnu/make/make-3.80.tar.gz</a>
		</p>
		<p>./configure --prefix=/usr &amp;&amp;<br />make &amp;&amp;<br />make install &amp;&amp;<br />chgrp root /usr/bin/make &amp;&amp;<br />chmod 755 /usr/bin/make</p>
<img src ="http://www.cppblog.com/jeromewen/aggbug/12679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jeromewen/" target="_blank">JeromeWen</a> 2006-09-18 13:51 <a href="http://www.cppblog.com/jeromewen/archive/2006/09/18/12679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>