AFL桩代码逻辑

共享内存中的bitmap结构 && forkserver机制
在这里插入图片描述

/* --- AFL MAIN PAYLOAD (32-BIT) --- */

.text
.att_syntax
.code32
.align 8


__afl_maybe_log:

    lahf
    seto %al                   //溢出置位

 /* Check if SHM region is already mapped. */

    movl  __afl_area_ptr, %edx   //检查共享内存有没有进行设置,判断是否为NULL    
    testl %edx, %edx    //如果为空,跳转到__afl__setup进行设置
    je    __afl_setup   
       
__afl_store:   
    
    /* Calculate and store hit for the code location specified in ecx. There   
        is a double-XOR way of doing this without tainting another register,   
        and we use it on 64-bit systems; but it's slower for 32-bit ones. */   
       
    #ifndef COVERAGE_ONLY
        movl __afl_prev_loc, %edi  ;edi = prev_location   ecx = cur_location
        xorl %ecx, %edi     ;cur_location ^ prev_location edi= cur_location ^ prev_location
        shrl $1, %ecx   ;prev_location = cur_location >> 1;
        movl %ecx, __afl_prev_loc   
    #else
        movl %ecx, %edi   
    #endif /* ^!COVERAGE_ONLY */
        
    #ifdef SKIP_COUNTS
        orb  $1, (%edx, %edi, 1)   
    #else                       
                               ;把共享内存单元中的计数数值加一, 也就是所谓的命中数
                               ;shared_mem[cur_location ^ prev_location]++;  
        incb (%edx, %edi, 1)   ;edx = shared_mem     edi= cur_location ^ prev_location
    #endif /* ^SKIP_COUNTS */   
       
__afl_return:   
       
    addb $127, %al   
    sahf   
    ret   ;难道说, 在运行完一次之后, 这个插桩的汇编程序又重新回到了__afl__maybe__log中了????
          ;也不是说运行完一次就回到最开始了,而是运行第一个桩之后就到了第二个桩呗?
       
.align 8   
       
__afl_setup:   ;初始化__afl__area__ptr,且只在运行到第一个桩时进行本次初始化
       
    /* Do not retry setup if we had previous failures. */   
    
    cmpb $0, __afl_setup_failure   
    jne  __afl_return   
    
    /* Map SHM, jumping to __afl_setup_abort if something goes wrong.   
        We do not save FPU/MMX/SSE registers here, but hopefully, nobody   
        will notice this early in the game. */   
    
    pushl %eax   
    pushl %ecx   
    
    pushl $.AFL_SHM_ENV   
    call  getenv   
    addl  $4, %esp   
    
    testl %eax, %eax   
    je    __afl_setup_abort   
    
    pushl %eax   
    call  atoi   
    addl  $4, %esp   
    
    pushl $0          /* shmat flags    */   
    pushl $0          /* requested addr */   
    pushl %eax        /* SHM ID         */   
    call  shmat   
    addl  $12, %esp   
    
    cmpl $-1, %eax   
    je   __afl_setup_abort   
    
    /* Store the address of the SHM region. */   
    
    movl %eax, __afl_area_ptr   
    movl %eax, %edx   
    
    popl %ecx   
    popl %eax   
       
__afl_forkserver:   
    
    /* Enter the fork server mode to avoid the overhead of execve() calls. */   
    
    pushl %eax   
    pushl %ecx   
    pushl %edx   
    
    /* Phone home and tell the parent that we're OK. (Note that signals with   
        no SA_RESTART will mess it up). If this fails, assume that the fd is   
        closed because we were execve()d from an instrumented binary, or because    
        the parent doesn't want to use the fork server. */   
    
    pushl $4          /* length    */   
    pushl $__afl_temp /* data      */   
    pushl $   STRINGIFY((FORKSRV_FD + 1))     /* file desc */   
    call  write   
    addl  $12, %esp   
    
    cmpl  $4, %eax   
    jne   __afl_fork_resume   
       
__afl_fork_wait_loop:   
    
    /* Wait for parent by reading from the pipe. Abort if read fails. */   
    
    pushl $4          /* length    */   
    pushl $__afl_temp /* data      */   
    pushl $   STRINGIFY(FORKSRV_FD)           /* file desc */   
    call  read   
    addl  $12, %esp   
    
    cmpl  $4, %eax   
    jne   __afl_die   
    
    /* Once woken up, create a clone of our process. This is an excellent use   
        case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly   
        caches getpid() results and offers no way to update the value, breaking   
        abort(), raise(), and a bunch of other things :-( */   
    
    call fork   
    
    cmpl $0, %eax   
    jl   __afl_die   ;创建子进程失败后,就退出程序
    je   __afl_fork_resume   ;如果是子进程的话, 进入afl_fork_resume中
    
    /* In parent process: write PID to pipe, then wait for child. */   
    
    movl  %eax, __afl_fork_pid          ;此时 eax中保存的是产生的子进程的pid, 将子进程pid保存到__afl_fork_pid中
    
    pushl $4              /* length    */   
    pushl $__afl_fork_pid /* data      */   
    pushl $   STRINGIFY((FORKSRV_FD + 1))         /* file desc */   
    call  write   
    addl  $12, %esp   
    
    pushl $0             /* no flags  */   ;等待子进程结束
    pushl $__afl_temp    /* status    */   
    pushl __afl_fork_pid /* PID       */   
    call  waitpid   ;成功:返回清理掉的子进程ID
    addl  $12, %esp   
    
    cmpl  $0, %eax   
    jle   __afl_die   ;如果子进程不是正常退出的话, 就结束掉整个进程
    
    /* Relay wait status to pipe, then loop back. */   
    
    pushl $4          /* length    */   
    pushl $__afl_temp /* data      */   
    pushl $   STRINGIFY((FORKSRV_FD + 1))     /* file desc */   
    call  write   
    addl  $12, %esp   
    
    jmp __afl_fork_wait_loop   
    
__afl_fork_resume:   
    
    /* In child process: close fds, resume execution. */   
    
    pushl $   STRINGIFY(FORKSRV_FD)      ;为什么要关闭fds呢? 不想让子进程干扰到父进程在管道中 写/读 数据
    call  close   
    
    pushl $   STRINGIFY((FORKSRV_FD + 1))      
    call  close   
    
    addl  $8, %esp   
    
    popl %edx   
    popl %ecx   
    popl %eax   
    jmp  __afl_store   
    
__afl_die:   
    
    xorl %eax, %eax   
    call _exit   
    
__afl_setup_abort:   
    
    /* Record setup failure so that we don't keep calling   
        shmget() / shmat() over and over again. */   
    
    incb __afl_setup_failure   
    popl %ecx   
    popl %eax   
    jmp __afl_return   
    
.AFL_VARS:   //
        ;.comm 声明未初始化的数据的通用内存区域
        .comm   __afl_area_ptr, 4, 32              //共享内存地址
        .comm   __afl_setup_failure, 1, 32         //标志位,如果标志置位,退出程序
    #ifndef COVERAGE_ONLY
        .comm   __afl_prev_loc, 4, 32              //上一个插桩位置(id为R(100)的随机数)
    #endif /* !COVERAGE_ONLY */
        .comm   __afl_fork_pid, 4, 32              //由fork产生的子进程的pid
        .comm   __afl_temp, 4, 32                  //缓冲区
    
.AFL_SHM_ENV:   
    .asciz \     SHM_ENV_VAR   \     
    
/* --- END --- */   
    ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值