• 使用ptrace向已运行进程中注入.so并执行相关函数


    这个总结的很好,从前一个项目也用到这中技术
    转自:http://blog.csdn.net/myarrow/article/details/9630377

    1. 简介

        使用ptrace向已运行进程中注入.so并执行相关函数,其中的“注入”二字的真正含义为:此.so被link到已运行进程(以下简称为:目标进程)空间中,从而.so中的函数在目标进程空间中有对应的地址,然后通过此地址便可在目标进程中进行调用。

         到底是如何注入的呢?

         本文实现方案为:在目标进程中,通过dlopen把需要注入的.so加载到目标进程的空间中。

    2. 如何让目标进程执行dlopen加载.so?

         显然,目标进程本来是没有实现通过dlopen来加载我们想注入的.so,为了实现此功能,我们需要目标进程执行一段我们实现的代码,此段代码的功能为通过dlopen来加载一个.so。

    3. 【加载.so的实现代码】

        加载需要注入的.so的实现代码如下所示:     

    1. .global _dlopen_addr_s       @dlopen函数在目标进程中的地址     注:以下全局变化在C中可读写  
    2. .global _dlopen_param1_s     @dlopen参数1<.so>在目标进程中的地址   
    3. .global _dlopen_param2_s     @dlopen参数2在目标进程中的地址  
    4.   
    5. .global _dlsym_addr_s        @dlsym函数在目标进程中的地址  
    6. .global _dlsym_param2_s      @dlsym参数2在目标进程中的地址,其实为函数名  
    7.   
    8. .global _dlclose_addr_s      @dlcose在目标进程中的地址  
    9.   
    10. .global _inject_start_s      @汇编代码段的起始地址  
    11. .global _inject_end_s        @汇编代码段的结束地址  
    12.   
    13. .global _inject_function_param_s  @hook_init参数在目标进程中的地址  
    14.   
    15. .global _saved_cpsr_s        @保存CPSR,以便执行完hook_init之后恢复环境  
    16. .global _saved_r0_pc_s       @保存r0-r15,以便执行完hook_init之后恢复环境  
    17.   
    18.   
    19. .data  
    20.   
    21. _inject_start_s:  
    22.     @ debug loop  
    23. 3:  
    24.     @sub r1, r1, #0  
    25.     @B 3b  
    26.   
    27.     @ dlopen  
    28.     ldr r1, _dlopen_param2_s        @设置dlopen第二个参数, flag  
    29.     ldr r0, _dlopen_param1_s        @设置dlopen第一个参数 .so  
    30.     ldr r3, _dlopen_addr_s          @设置dlopen函数  
    31.     blx r3                          @执行dlopen函数,返回值位于r0中  
    32.     subs r4, r0, #0                 @把dlopen的返回值soinfo保存在r4中,以方便后面dlclose使用  
    33.     beq 2f  
    34.   
    35.     @dlsym  
    36.     ldr r1, _dlsym_param2_s        @设置dlsym第二个参数,第一个参数已经在r0中了  
    37.     ldr r3, _dlsym_addr_s          @设置dlsym函数  
    38.     blx r3                         @执行dlsym函数,返回值位于r0中  
    39.     subs r3, r0, #0                @把返回值<hook_init在目标进程中的地址>保存在r3中  
    40.     beq 1f  
    41.   
    42.     @call our function  
    43.     ldr r0, _inject_function_param_s  @设置hook_init第一个参数  
    44.         blx r3                            @执行hook_init  
    45.     subs r0, r0, #0  
    46.     beq 2f  
    47.   
    48. 1:  
    49.     @dlclose                          
    50.     mov r0, r4                        @把dlopen的返回值设为dlcose的第一个参数  
    51.     ldr r3, _dlclose_addr_s           @设置dlclose函数  
    52.     blx r3                            @执行dlclose函数  
    53.   
    54. 2:  
    55.     @restore context  
    56.     ldr r1, _saved_cpsr_s             @恢复CPSR  
    57.     msr cpsr_cf, r1  
    58.     ldr sp, _saved_r0_pc_s            @恢复寄存器r0-r15  
    59.     ldmfd sp, {r0-pc}  
    60.       
    61.   
    62.       
    63.   
    64. _dlopen_addr_s:                           @初始化_dlopen_addr_s  
    65. .word 0x11111111  
    66.   
    67. _dlopen_param1_s:  
    68. .word 0x11111111  
    69.   
    70. _dlopen_param2_s:  
    71. .word 0x2                                 @RTLD_GLOBAL  
    72.   
    73. _dlsym_addr_s:  
    74. .word 0x11111111  
    75.   
    76. _dlsym_param2_s:  
    77. .word 0x11111111  
    78.   
    79. _dlclose_addr_s:  
    80. .word 0x11111111  
    81.   
    82. _inject_function_param_s:  
    83. .word 0x11111111  
    84.   
    85. _saved_cpsr_s:  
    86. .word 0x11111111  
    87.   
    88. _saved_r0_pc_s:  
    89. .word 0x11111111  
    90.   
    91.   
    92. _inject_end_s:                     @代码结束地址  
    93.   
    94. .space 0x400, 0                    @代码段空间大小  
    95.   
    96. .end  

    4. 如何把【加载.so的实现代码】写入目标进程并启动执行?

       为了把【加载.so的实现代码】写入目标进程,主要有以下两步操作:

       1) 在目标进程中找到存放【加载.so的实现代码】的空间(通过mmap实现)

       2) 把【加载.so的实现代码】写入目标进程指定的空间

       3) 启动执行

    4.1 在目标进程中找到存放【加载.so的实现代码】的空间

        通过mmap来实现,其实现步骤如下:

       1) 获取目标进程中mmap地址
       2) 把mmap参数据放入r0-r3,另外两个写入目标进程sp 
       3) pc设置为mmap地址,lr设置为0
       4) 把准备好的寄存器写入目标进程(PTRACE_SETREGS),并启动目标进程运行(PTRACE_CONT)
       5) 分配的内存首地址位于r0 (PTRACE_GETREGS)

    4.2 为【加载.so的实现代码】中的全局变量赋值

       1) 获取目标进程中dlopen地址并赋值给_dlopen_addr_s

       2) 获取目标进程中dlsym地址并赋值给_dlsym_addr_s

       3) 获取目标进程中dlclose地址并赋值给_dlclose_addr_s

       4) 把需要加载的.so的路径放入 汇编代码中,并获取此路径在目标进程中的地址然后赋值给_dlopen_param1_s

       5) 把需要加载的.so中的hook_init放入 汇编代码中,并获取此路径在目标进程中的地址然后赋值给_dlsym_param2_s

       6) 把目标进程中的cpsr保存在_saved_cpsr_s中

       7) 把目标进程中的r0-r15存入汇编代码中,并获取此变量在目标进程中的地址然后赋值给_saved_r0_pc_s

       8) 通过ptrace( PTRACE_POKETEXT,...)把汇编代码写入目标进程中,起始地址由前面的mmap所分配

       9) 把目标进程的pc设置为汇编代码的起始地址,然后调用ptrace(PTRACE_DETACH,...)以启动目标进程执行

    5. 把汇编代码写入目标进程并执行的实现代码

    5.1 主函数 writecode_to_targetproc

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <asm/ptrace.h>  
    4. #include <asm/user.h>  
    5. #include <asm/ptrace.h>  
    6. #include <sys/wait.h>  
    7. #include <sys/mman.h>  
    8. #include <dlfcn.h>  
    9. #include <dirent.h>  
    10. #include <unistd.h>  
    11. #include <string.h>  
    12. #include <android/log.h>  
    13. #include <sys/types.h>  
    14. #include <sys/socket.h>  
    15. #include <netinet/in.h>  
    16. #include <sys/stat.h>  
    17.   
    18. #define MAX_PATH 0x100  
    19. #define REMOTE_ADDR( addr, local_base, remote_base ) ( (uint32_t)(addr) + (uint32_t)(remote_base) - (uint32_t)(local_base) )  
    20.   
    21. /* write the assembler code into target proc, 
    22.  * and invoke it to execute 
    23.  */  
    24. int writecode_to_targetproc(   
    25.     pid_t target_pid, // target process pid  
    26.     const char *library_path, // the path of .so that will be   
    27.                               // upload to target process   
    28.     const char *function_name, // .so init fucntion e.g. hook_init  
    29.     void *param, // the parameters of init function  
    30.     size_t param_size ) // number of parameters   
    31. {  
    32.     int ret = -1;  
    33.     void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;  
    34.     void *local_handle, *remote_handle, *dlhandle;  
    35.     uint8_t *map_base;  
    36.     uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;  
    37.   
    38.     struct pt_regs regs, original_regs;  
    39.   
    40.     // extern global variable in the assembler code   
    41.     extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s,   
    42.             _dlsym_addr_s, _dlsym_param2_s, _dlclose_addr_s,   
    43.             _inject_start_s, _inject_end_s, _inject_function_param_s,   
    44.             _saved_cpsr_s, _saved_r0_pc_s;  
    45.   
    46.     uint32_t code_length;  
    47.   
    48.     long parameters[10];  
    49.   
    50.     // make target_pid as its child process and stop  
    51.     if ( ptrace_attach( target_pid ) == -1 )  
    52.         return -1;  
    53.   
    54.     // get the values of 18 registers from target_pid  
    55.     if ( ptrace_getregs( target_pid, ®s ) == -1 )  
    56.         goto exit;  
    57.   
    58.     // save original registers   
    59.     memcpy( &original_regs, ®s, sizeof(regs) );  
    60.   
    61.     // get mmap address from target_pid  
    62.     // the mmap is the address of mmap in the cur process  
    63.     mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );  
    64.   
    65.     // set mmap parameters  
    66.     parameters[0] = 0;  // addr  
    67.     parameters[1] = 0x4000; // size  
    68.     parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot  
    69.     parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags  
    70.     parameters[4] = 0; //fd  
    71.     parameters[5] = 0; //offset  
    72.   
    73.     // execute the mmap in target_pid  
    74.     if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, ®s ) == -1 )  
    75.         goto exit;  
    76.   
    77.     // get the return values of mmap <in r0>  
    78.     if ( ptrace_getregs( target_pid, ®s ) == -1 )  
    79.         goto exit;  
    80.   
    81.     // get the start address for assembler code  
    82.     map_base = (uint8_t *)regs.ARM_r0;  
    83.   
    84.     // get the address of dlopen, dlsym and dlclose in target process  
    85.     dlopen_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlopen );  
    86.     dlsym_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlsym );  
    87.     dlclose_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlclose );  
    88.   
    89.     // set the start address for assembler code in target process  
    90.     remote_code_ptr = map_base + 0x3C00;  
    91.   
    92.     // set the start address for assembler code in cur process  
    93.     local_code_ptr = (uint8_t *)&_inject_start_s;  
    94.   
    95.     // set global variable of assembler code  
    96.     // and these address is in the target process  
    97.     _dlopen_addr_s = (uint32_t)dlopen_addr;  
    98.     _dlsym_addr_s = (uint32_t)dlsym_addr;  
    99.     _dlclose_addr_s = (uint32_t)dlclose_addr;  
    100.   
    101.     code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;  
    102.       
    103.     dlopen_param1_ptr = local_code_ptr + code_length + 0x20;  
    104.     dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;  
    105.     saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;  
    106.     inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;  
    107.   
    108.   
    109.     // save library path to assembler code global variable  
    110.     strcpy( dlopen_param1_ptr, library_path );  
    111.     _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );  
    112.       
    113.   
    114.     // save function name to assembler code global variable  
    115.     strcpy( dlsym_param2_ptr, function_name );  
    116.     _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );  
    117.   
    118.     // save cpsr to assembler code global variable  
    119.     _saved_cpsr_s = original_regs.ARM_cpsr;  
    120.   
    121.     // save r0-r15 to assembler code global variable  
    122.     memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15  
    123.     _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );  
    124.   
    125.     // save function parameters to assembler code global variable  
    126.     memcpy( inject_param_ptr, param, param_size );  
    127.     _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );  
    128.   
    129.     // write the assembler code into target process  
    130.     // now the values of global variable is in the target process space  
    131.     ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );  
    132.   
    133.     memcpy( ®s, &original_regs, sizeof(regs) );  
    134.   
    135.     // set sp and pc to the start address of assembler code  
    136.     regs.ARM_sp = (long)remote_code_ptr;  
    137.     regs.ARM_pc = (long)remote_code_ptr;  
    138.   
    139.     // set registers for target process  
    140.     ptrace_setregs( target_pid, ®s );  
    141.   
    142.     // make the target_pid is not a child process of cur process  
    143.     // and make target_pid continue to running  
    144.     ptrace_detach( target_pid );  
    145.   
    146.     // now finish it successfully  
    147.     ret = 0;  
    148.   
    149. exit:  
    150.     return ret;  
    151. }  

    5.2 attach目标进程ptrace_attach

    1. int ptrace_attach( pid_t pid )  
    2. {  
    3.     // after PTRACE_ATTACH, the proc<pid> will stop  
    4.     if ( ptrace( PTRACE_ATTACH, pid, NULL, 0  ) < 0 )  
    5.     {  
    6.         perror( "ptrace_attach" );  
    7.         return -1;  
    8.     }  
    9.   
    10.     // wait proc<pid> stop  
    11.     waitpid( pid, NULL, WUNTRACED );  
    12.   
    13.     // after PTRACE_SYSCALL, the proc<pid> will continue,  
    14.     // but when exectue sys call function, proc<pid> will stop  
    15.     if ( ptrace( PTRACE_SYSCALL, pid, NULL, 0  ) < 0 )  
    16.     {  
    17.         perror( "ptrace_syscall" );  
    18.         return -1;  
    19.     }  
    20.   
    21.     // wait proc<pid> stop  
    22.     waitpid( pid, NULL, WUNTRACED );  
    23.   
    24.     return 0;  
    25. }  

    5.3 获取目标进程寄存器值ptrace_getregs

    1. int ptrace_getregs( pid_t pid, struct pt_regs* regs )  
    2. {  
    3.     if ( ptrace( PTRACE_GETREGS, pid, NULL, regs ) < 0 )  
    4.     {  
    5.         perror( "ptrace_getregs: Can not get register values" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  


    5.4 获取目标进程中指定模块中指定函数的地址get_remote_addr

    1.    
    2. /* find the start address of module whose name is module_name  
    3.  * in the designated process 
    4.  */  
    5. void* get_module_base( pid_t pid, const char* module_name )  
    6. {  
    7.     FILE *fp;  
    8.     long addr = 0;  
    9.     char *pch;  
    10.     char filename[32];  
    11.     char line[1024];  
    12.   
    13.     if ( pid < 0 )  
    14.     {  
    15.         /* self process */  
    16.         snprintf( filename, sizeof(filename), "/proc/self/maps", pid );  
    17.     }  
    18.     else  
    19.     {  
    20.         snprintf( filename, sizeof(filename), "/proc/%d/maps", pid );  
    21.     }  
    22.   
    23.     fp = fopen( filename, "r" );  
    24.   
    25.     if ( fp != NULL )  
    26.     {  
    27.         while ( fgets( line, sizeof(line), fp ) )  
    28.         {  
    29.             if ( strstr( line, module_name ) )  
    30.             {  
    31.                 pch = strtok( line, "-" );  
    32.                 addr = strtoul( pch, NULL, 16 );  
    33.   
    34.                 if ( addr == 0x8000 )  
    35.                     addr = 0;  
    36.   
    37.                 break;  
    38.             }  
    39.         }  
    40.         fclose( fp ) ;  
    41.     }  
    42.   
    43.     return (void *)addr;  
    44. }  
    45.   
    46. void* get_remote_addr( pid_t target_pid, const char* module_name, void* local_addr )  
    47. {  
    48.     void* local_handle, *remote_handle;  
    49.   
    50.     local_handle = get_module_base( -1, module_name );  
    51.     remote_handle = get_module_base( target_pid, module_name );  
    52.   
    53.     return (void *)( (uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle );  
    54. }  

    5.5 在目标进程中执行指定函数ptrace_call

    1. int ptrace_call( pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs )  
    2. {  
    3.     uint32_t i;  
    4.   
    5.     // put the first 4 parameters into r0-r3  
    6.     for ( i = 0; i < num_params && i < 4; i ++ )  
    7.     {  
    8.         regs->uregs[i] = params[i];  
    9.     }  
    10.   
    11.     // push remained params into stack  
    12.     if ( i < num_params )  
    13.     {  
    14.         regs->ARM_sp -= (num_params - i) * sizeof(long) ;  
    15.         ptrace_writedata( pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long) );  
    16.     }  
    17.     // set the pc to func <e.g: mmap> that will be executed  
    18.     regs->ARM_pc = addr;  
    19.     if ( regs->ARM_pc & 1 )  
    20.     {  
    21.         /* thumb */  
    22.         regs->ARM_pc &= (~1u);  
    23.         regs->ARM_cpsr |= CPSR_T_MASK;  
    24.     }  
    25.     else  
    26.     {  
    27.         /* arm */  
    28.         regs->ARM_cpsr &= ~CPSR_T_MASK;  
    29.     }  
    30.   
    31.     // when finish this func, pid will stop  
    32.     regs->ARM_lr = 0;      
    33.   
    34.     // set the regsister and start to execute  
    35.     if ( ptrace_setregs( pid, regs ) == -1   
    36.         || ptrace_continue( pid ) == -1 )  
    37.     {  
    38.         return -1;  
    39.     }  
    40.   
    41.     // wait pid finish work and stop  
    42.     waitpid( pid, NULL, WUNTRACED );  
    43.   
    44.     return 0;  
    45. }  

    5.6 把代码写入目标进程指定地址ptrace_writedata

    1. int ptrace_writedata( pid_t pid, uint8_t *dest, uint8_t *data, size_t size )  
    2. {  
    3.     uint32_t i, j, remain;  
    4.     uint8_t *laddr;  
    5.   
    6.     union u {  
    7.         long val;  
    8.         char chars[sizeof(long)];  
    9.     } d;  
    10.   
    11.     j = size / 4;  
    12.     remain = size % 4;  
    13.   
    14.     laddr = data;  
    15.   
    16.     for ( i = 0; i < j; i ++ )  
    17.     {  
    18.         memcpy( d.chars, laddr, 4 );  
    19.         ptrace( PTRACE_POKETEXT, pid, dest, d.val );  
    20.   
    21.         dest  += 4;  
    22.         laddr += 4;  
    23.     }  
    24.   
    25.     if ( remain > 0 )  
    26.     {  
    27.         d.val = ptrace( PTRACE_PEEKTEXT, pid, dest, 0 );  
    28.         for ( i = 0; i < remain; i ++ )  
    29.         {  
    30.             d.chars[i] = *laddr ++;  
    31.         }  
    32.   
    33.         ptrace( PTRACE_POKETEXT, pid, dest, d.val );  
    34.           
    35.     }  
    36.   
    37.     return 0;  
    38. }  

    5.7 设置目标进程寄存器ptrace_setregs

    1. int ptrace_setregs( pid_t pid, struct pt_regs* regs )  
    2. {  
    3.     if ( ptrace( PTRACE_SETREGS, pid, NULL, regs ) < 0 )  
    4.     {  
    5.         perror( "ptrace_setregs: Can not set register values" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  

    5.8 detach目标进程ptrace_detach

    1. int ptrace_detach( pid_t pid )  
    2. {  
    3.     if ( ptrace( PTRACE_DETACH, pid, NULL, 0 ) < 0 )  
    4.     {  
    5.         perror( "ptrace_detach" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  


    6.  需要被加载的.so

        需要被加载的.so例子程序如下,其目的是替换目标进程libapp.so中的strlen函数。其主要实现见hook_init。

    1. int g_isInit = 0;      
    2. pthread_t g_hThread;       
    3.   
    4. __attribute__((visibility("default"))) void hook_init( char *args )  
    5. {  
    6.    if( g_isInit == 1 )  
    7.    {  
    8.       printf("i am already in!");  
    9.       return;  
    10.    }  
    11.   
    12.    void* soHandle = NULL;  
    13.      
    14.    // the libapp.so is a .so of target process, and it call strcmp  
    15.    soHandle  = dlopen( "libapp.so", RTLD_GLOBAL );  
    16.    if( soHandle != NULL )  
    17.    {  
    18.       g_realstrcmp = NULL;  
    19.       replaceFunc( soHandle, "strcmp", my_strcmp, (void**)&g_realstrcmp );  
    20.         
    21.       int ret = pthread_create( &g_hThread, NULL, my_thread, NULL );  
    22.       if( ret != 0 )  
    23.       {  
    24.          printf("create thread error:%d", ret );  
    25.       }  
    26.         
    27.       g_isInit = 1;  
    28.    }  
    29.      
    30. }  

    6.1 替换函数replaceFunc

    1. // replace function of libapp.so  
    2. // e.g: replace strcmp of libapp.so with my_strcmp  
    3. void replaceFunc(void *handle,const char *name, void* pNewFun, void** pOldFun )  
    4. {  
    5.   
    6.    if(!handle)  
    7.       return;  
    8.         
    9.    soinfo *si = (soinfo*)handle;     
    10.    Elf32_Sym *symtab = si->symtab;    
    11.    const char *strtab = si->strtab;    
    12.    Elf32_Rel *rel = si->plt_rel;  
    13.    unsigned count = si->plt_rel_count;   
    14.    unsigned idx;   
    15.   
    16.    // these external functions that are called by libapp.so   
    17.    // is in the plt_rel  
    18.    for(idx=0; idx<count; idx++)   
    19.    {    
    20.       unsigned type = ELF32_R_TYPE(rel->r_info);    
    21.       unsigned sym = ELF32_R_SYM(rel->r_info);    
    22.       unsigned reloc = (unsigned)(rel->r_offset + si->base);    
    23.       char *sym_name = (char *)(strtab + symtab[sym].st_name);   
    24.         
    25.       if(strcmp(sym_name, name)==0)   
    26.       {   
    27.          *pOldFun = (void *)*((unsigned*)reloc);   
    28.           *((unsigned*)reloc)= pNewFun;  
    29.          break;  
    30.       }   
    31.       rel++;    
    32.    }   
    33. }  

    6.2 新函数及其它函数

    1. // global function variable, save the address of strcmp of libapp.so  
    2. int (*g_realstrcmp)(const char *s1, const char *s2);  
    3.   
    4. // my strcmp function  
    5. int my_strcmp(const char *s1, const char *s2)  
    6. {  
    7.     if( g_realstrcmp != NULL )  
    8.     {  
    9.         int nRet = g_realstrcmp( s1, s2 );  
    10.         printf("***%s: s1=%s, s2=%s ",__FUNCTION__, s1, s2 );  
    11.         return nRet;  
    12.     }  
    13.   
    14.     return -1;  
    15. }  
    16.   
    17.   
    18. // create a thread  
    19. void* my_thread( void* pVoid )  
    20. {  
    21.     int sock;  
    22.     sock = socket(AF_INET, SOCK_DGRAM, 0);  
    23.     if( sock < -1 )  
    24.     {  
    25.       printf("create socket failed! ");  
    26.       return 0;  
    27.     }  
    28.   
    29.     struct sockaddr_in addr_serv;    
    30.     int len;    
    31.     memset(&addr_serv, 0, sizeof(struct sockaddr_in));    
    32.     addr_serv.sin_family = AF_INET;    
    33.     addr_serv.sin_port = htons(9999);     
    34.     addr_serv.sin_addr.s_addr = inet_addr("127.0.0.1");    
    35.     len = sizeof(addr_serv);    
    36.   
    37.     int flags = fcntl( sock, F_GETFL, 0);   
    38.     fcntl( sock, F_SETFL, flags | O_NONBLOCK);  
    39.     int nPreState = -1;  
    40.     unsigned char data=0;  
    41.     while( 1 )  
    42.     {  
    43.         data++;  
    44.         sendto( sock, &data,  sizeof( data ), 0, (struct sockaddr *)&addr_serv, sizeof( addr_serv ) );  
    45.         usleep( 30000 );  
    46.     }  
    47. }  
  • 相关阅读:
    第六周学习进度总结
    构建之法阅读笔记03
    文件操作
    数组相关
    compareTo
    我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 比如n=3时,2*3的矩形块有3种覆盖方法:
    从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行
    整数中1出现的次数
    Java泛型(看着好有用)
    输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
  • 原文地址:https://www.cnblogs.com/fly-fish/p/3835958.html
Copyright © 2020-2023  润新知