Beispiel #1
0
/* 
 * make an assignment.
 */
static int execute_assign(struct filter_op *fop, struct packet_object *po)
{
   /* initialize to the beginning of the packet */
   u_char *base = po->L2.header;

   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot modify packets in unoffensive mode");
   
   DEBUG_MSG("filter engine: execute_assign: L%d O%d S%d", fop->op.assign.level, fop->op.assign.offset, fop->op.assign.size);
   
   /* 
    * point to the right base.
    */
   switch (fop->op.assign.level) {
      case 2:
         base = po->L2.header;
         break;
      case 3:
         base = po->L3.header;
         break;
      case 4:
         base = po->L4.header;
         break;
      case 5:
         base = po->DATA.data;
         break;
      default:
         JIT_FAULT("unsupported assignment level [%d]", fop->op.assign.level);
         break;
   }

   /* 
    * get the value with the proper size.
    * 0 is a special case for strings (even binary) 
    */
   switch (fop->op.assign.size) {
      case 0:
         memcpy(base + fop->op.assign.offset, fop->op.assign.string, fop->op.assign.slen);
         break;
      case 1:
         *(u_int8 *)(base + fop->op.assign.offset) = (fop->op.assign.value & 0xff);
         break;
      case 2:
         *(u_int16 *)(base + fop->op.assign.offset) = ntohs(fop->op.assign.value & 0xffff); 
         break;
      case 4:
         *(u_int32 *)(base + fop->op.assign.offset) = ntohl(fop->op.assign.value & 0xffffffff);
         break;
      default:
         JIT_FAULT("unsupported assign size [%d]", fop->op.assign.size);
         break;
   }
      
   /* mark the packet as modified */
   po->flags |= PO_MODIFIED;

   return FLAG_TRUE;
}
Beispiel #2
0
/*
 * inject a file into the communication
 */
static int func_inject(struct filter_op *fop, struct packet_object *po)
{
   int fd;
   void *file;
   size_t size, ret;
   
   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot inject packets in unoffensive mode");
   

   DEBUG_MSG("filter engine: func_inject %s", fop->op.func.string);
   
   /* open the file */
   if ((fd = open(fop->op.func.string, O_RDONLY | O_BINARY)) == -1) {
      USER_MSG("filter engine: inject(): File not found (%s)\n", fop->op.func.string);
      return -EFATAL;
   }

   /* get the size */
   size = lseek(fd, 0, SEEK_END);

   /* load the file in memory */
   SAFE_CALLOC(file, size, sizeof(char));
 
   /* rewind the pointer */
   lseek(fd, 0, SEEK_SET);
   
   ret = read(fd, file, size);
   
   close(fd);

   if (ret != size)
      FATAL_MSG("Cannot read the file into memory");
 
   /* check if we are overflowing pcap buffer */
   if(GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + size)
      JIT_FAULT("injected file too long");
         
   /* copy the file into the buffer */
   memcpy(po->DATA.data + po->DATA.len, file, size);

   /* Adjust packet len and delta */
   po->DATA.delta += size;
   po->DATA.len += size;    

   /* mark the packet as modified */
   po->flags |= PO_MODIFIED;
   
   /* unset the flag to be dropped */
   if (po->flags & PO_DROPPED)
      po->flags ^= PO_DROPPED;

   /* close and unmap the file */
   SAFE_FREE(file);
   
   return ESUCCESS;
}
Beispiel #3
0
/*
 * inject output of a executable into the communication
 */
static int func_execinject(struct filter_op *fop, struct packet_object *po)
{
   FILE *pstream = NULL;
   unsigned char *output = NULL;
   size_t n = 0, offset = 0, size = 128;
   unsigned char buf[size];
   
   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot inject packets in unoffensive mode");
   

   DEBUG_MSG("filter engine: func_execinject %s", fop->op.func.string);
   
   /* open the pipe */
   if ((pstream = popen((const char*)fop->op.func.string, "r")) == NULL) {
      USER_MSG("filter engine: execinject(): Command not found (%s)\n", fop->op.func.string);
      return -E_FATAL;
   }
   
   while ((n = read(fileno(pstream), buf, size)) != 0) {
      if (output == NULL) {
         SAFE_CALLOC(output, offset+n, sizeof(unsigned char));
      }
      else {
         SAFE_REALLOC(output, sizeof(unsigned char)*(offset+n));
      }

      memcpy(output+offset, buf, n);
      offset += n;
   }
   
   /* close pipe stream */
   pclose(pstream);

   /* check if we are overflowing pcap buffer */
   if(GBL_PCAP->snaplen - (po->L4.header - (po->packet + po->L2.len) + po->L4.len) <= po->DATA.len + (unsigned)offset)
      JIT_FAULT("injected output too long");
         
   /* copy the output into the buffer */
   memcpy(po->DATA.data + po->DATA.len, output, offset);

   /* Adjust packet len and delta */
   po->DATA.delta += offset;
   po->DATA.len += offset;    

   /* mark the packet as modified */
   po->flags |= PO_MODIFIED;
   
   /* unset the flag to be dropped */
   if (po->flags & PO_DROPPED)
      po->flags ^= PO_DROPPED;

   /* free memory */
   SAFE_FREE(output);
   
   return E_SUCCESS;
}
Beispiel #4
0
/*
 * log the packet to a file
 */
static int func_log(struct filter_op *fop, struct packet_object *po)
{
   int fd;

   DEBUG_MSG("filter engine: func_log");
   
   /* open the file */
   fd = open(fop->op.func.string, O_CREAT | O_APPEND | O_RDWR | O_BINARY, 0600);
   if (fd == -1) {
      USER_MSG("filter engine: Cannot open file %s\n", fop->op.func.string);
      return -EFATAL;
   }

   /* which data should I have to log ? */
   switch(fop->op.func.level) {
      case 5:
         if (write(fd, po->DATA.data, po->DATA.len) < 0)
            USER_MSG("filter engine: Cannot write to file...%d\n", errno);
         break;
      case 6:
         if (write(fd, po->DATA.disp_data, po->DATA.disp_len) < 0)
            USER_MSG("filter engine: Cannot write to file...\n");
         break;
      default:
         JIT_FAULT("unsupported log level [%d]", fop->op.func.level);
         break;
   }

   /* close the file */
   close(fd);
   
   return ESUCCESS;
}
Beispiel #5
0
/*
 * search a string with a regex and return TRUE if found
 */
static int func_regex(struct filter_op *fop, struct packet_object *po)
{
   switch (fop->op.func.level) {
      case 5:
         /* search in the real packet */
         if (regexec(fop->op.func.ropt->regex, po->DATA.data, 0, NULL, 0) == 0)
            return ESUCCESS;
         break;
      case 6:
         /* search in the decoded/decrypted packet */
         if (regexec(fop->op.func.ropt->regex, po->DATA.disp_data, 0, NULL, 0) == 0)
            return ESUCCESS;
         break;
      default:
         JIT_FAULT("unsupported regex level [%d]", fop->op.func.level);
         break;
   }

   return -ENOTFOUND;
}
Beispiel #6
0
/*
 * search a string and return TRUE if found
 */
static int func_search(struct filter_op *fop, struct packet_object *po)
{
   switch (fop->op.func.level) {
      case 5:
         /* search in the real packet */
         if (memmem(po->DATA.data, po->DATA.len, fop->op.func.string, fop->op.func.slen))
            return ESUCCESS;
         break;
      case 6:
         /* search in the decoded/decrypted packet */
         if (memmem(po->DATA.disp_data, po->DATA.disp_len, fop->op.func.string, fop->op.func.slen))
            return ESUCCESS;
         break;
      default:
         JIT_FAULT("unsupported search level [%d]", fop->op.func.level);
         break;
   }
   
   return -ENOTFOUND;
}
Beispiel #7
0
/*
 * JIT interpreter for binary filters.
 * it process the filter_ops and apply the instructions
 * on the given packet object
 */
static int filter_engine(struct filter_op *fop, struct packet_object *po)
{
   u_int32 eip = 0;
   u_int32 flags = 0;
      #define FLAG_FALSE   0
      #define FLAG_TRUE    1
  
   /* sanity check */
   BUG_IF(fop == NULL);

   FILTERS_LOCK;

   /* loop until EXIT */
   while (fop[eip].opcode != FOP_EXIT) {

      switch (fop[eip].opcode) {
         case FOP_TEST:
            if (execute_test(&fop[eip], po) == FLAG_TRUE)
               flags |= FLAG_TRUE;
            else
               flags &= ~(FLAG_TRUE);
            
            break;
            
         case FOP_ASSIGN:
            execute_assign(&fop[eip], po);
            /* assignment always returns true */
            flags |= FLAG_TRUE;
            
            break;
            
         case FOP_INC:
         case FOP_DEC:
            execute_incdec(&fop[eip], po);
            /* inc/dec always return true */
            flags |= FLAG_TRUE;
            
            break;
            
         case FOP_FUNC:
            if (execute_func(&fop[eip], po) == FLAG_TRUE)
               flags |= FLAG_TRUE;
            else
               flags &= ~(FLAG_TRUE);

            break;
            
         case FOP_JMP:
            /* jump the the next eip */
            eip = fop[eip].op.jmp;
            continue;

            break;
            
         case FOP_JTRUE:
            /* jump the the next eip if the TRUE FLAG is set*/
            if (flags & FLAG_TRUE) {
               eip = fop[eip].op.jmp;
               continue;
            }
            break;
            
         case FOP_JFALSE:
            /* jump the the next eip if the TRUE FLAG is NOT set */
            if (!(flags & FLAG_TRUE)) {
               eip = fop[eip].op.jmp;
               continue;
            }
            break;
            
         default:
            FILTERS_UNLOCK;
            JIT_FAULT("unsupported opcode [%d] (execution interrupted)", fop[eip].opcode);
            break;
      }
    
      /* autoincrement the instruction pointer */
      eip++;
   }
   
   FILTERS_UNLOCK;

   return 0;
}
Beispiel #8
0
/* 
 * replace a string in the packet object DATA.data
 */
static int func_replace(struct filter_op *fop, struct packet_object *po)
{
   u_int8 *ptr;
   u_int8 *end;
   size_t len;
   size_t slen = fop->op.func.slen;
   size_t rlen = fop->op.func.rlen;
  
   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot modify packets in unoffensive mode");
   
   /* check if it exist at least one */
   if (!memmem(po->DATA.data, po->DATA.len, fop->op.func.string, fop->op.func.slen) )
      return -ENOTFOUND;

   DEBUG_MSG("filter engine: func_replace");

   /* 
    * XXX BIG WARNING:
    * maxlen is GBL_PCAP->snaplen, but we can't 
    * rely on this forever...
    */
   
   /* take the beginning and the end of the data */
   ptr = po->DATA.data;
   end = ptr + po->DATA.len;
   
   /* do the replacement */
   do {
      /* the len of the buffer to be analized */
      len = end - ptr;

      /* search the string */
      ptr = memmem(ptr, len, fop->op.func.string, slen);

      /* string no found, exit */
      if (ptr == NULL)
         break;
	 
      /* update the len */
      len = end - ptr - slen;
      
      /* set the delta */
      po->DATA.delta += rlen - slen;
      po->DATA.len += rlen - slen;
      
      /* check if we are overflowing pcap buffer */
      BUG_IF(po->DATA.data < po->packet);
      BUG_IF((u_int16)(GBL_PCAP->snaplen - (po->DATA.data - po->packet)) <=  po->DATA.len);
      
      /* move the buffer to make room for the replacement string */   
      memmove(ptr + rlen, ptr + slen, len); 
      /* copy the replacemente string */
      memcpy(ptr, fop->op.func.replace, rlen);
      /* move the ptr after the replaced string */
      ptr += rlen; 
      /* adjust the new buffer end */
      end += rlen - slen;
                                                            
      /* mark the packet as modified */
      po->flags |= PO_MODIFIED;

   } while(ptr != NULL && ptr < end);
   
   return ESUCCESS;
}
Beispiel #9
0
/*
 * evaluate a perl regex and return TRUE if found
 */
static int func_pcre(struct filter_op *fop, struct packet_object *po)
{
#ifndef HAVE_PCRE
   JIT_FAULT("pcre_regex support not compiled in ettercap");
   return -ENOTFOUND;
#else
   int ovec[PCRE_OVEC_SIZE];
   int ret;
   
   DEBUG_MSG("filter engine: func_pcre");
   
   memset(&ovec, 0, sizeof(ovec));
   
   switch (fop->op.func.level) {
      case 5:
         
         /* search in the real packet */
         if ( (ret = pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.data, po->DATA.len, 0, 0, ovec, sizeof(ovec) / sizeof(*ovec))) < 0)
            return -ENOTFOUND;

         /* the pcre wants to modify the packet */
         if (fop->op.func.replace) {
            u_char *replaced;
            u_char *q = fop->op.func.replace;
            size_t i, nlen = 0;

            /* don't modify if in unoffensive mode */
            if (GBL_OPTIONS->unoffensive)
               JIT_FAULT("Cannot modify packets in unoffensive mode");
             
            /* 
             * the replaced string will not be larger than
             * the matched string + replacement string
             */
            SAFE_CALLOC(replaced, ovec[1] + strlen(q) + 1, sizeof(char));
          
            po->flags |= PO_MODIFIED;

            /* make the replacement */
            for (i = 0; i < fop->op.func.rlen; i++) {
               
               /* there is a position marker */
               if (q[i] == '$' && q[i - 1] != '\\') {
                  
                  int marker = atoi(q + i + 1);
                  int t = ovec[marker * 2];
                  int r = ovec[marker * 2 + 1];
                  
                  /* skip the chars of the marker */
                  while (q[++i + 1] != ' ' && q[i] < q[strlen(q)] );
                  
                  /* check if the requested marker was found in the pce */
                  if (marker > ret - 1 || marker == 0)
                     JIT_FAULT("Too many marker for this pcre expression");

                  /* copy the sub-string in place of the marker */
                  for ( ; t < r; t++) 
                     replaced[nlen++] = po->DATA.data[t];
                  
               /* the $ is escaped, copy it */
               } else if (q[i] == '\\' && q[i + 1] == '$') {
                  replaced[nlen++] = q[++i];
               /* all the other chars are copied as they are */
               } else {
                  replaced[nlen++] = q[i];
               }
            }
            
            /* calculate the delta */
            po->DATA.delta += nlen - po->DATA.len;
            po->DATA.len = nlen;
	    
            /* check if we are overflowing pcap buffer */
            BUG_IF(po->DATA.data < po->packet);
            BUG_IF((u_int16)(GBL_PCAP->snaplen - (po->DATA.data - po->packet)) <= nlen);

            /* copy the temp buffer on the original packet */
            memcpy(po->DATA.data, replaced, nlen);
                       
            SAFE_FREE(replaced);
         }
         
         break;
      case 6:
         /* search in the decoded one */
         if ( pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.disp_data, po->DATA.disp_len, 0, 0, NULL, 0) < 0)
            return -ENOTFOUND;
         break;
      default:
         JIT_FAULT("unsupported pcre_regex level [%d]", fop->op.func.level);
         break;
   }

   return ESUCCESS;
#endif
}
Beispiel #10
0
/* 
 * make an increment or decrement.
 */
static int execute_incdec(struct filter_op *fop, struct packet_object *po)
{
   /* initialize to the beginning of the packet */
   u_char *base = po->L2.header;

   /* check the offensiveness */
   if (GBL_OPTIONS->unoffensive)
      JIT_FAULT("Cannot modify packets in unoffensive mode");
   
   DEBUG_MSG("filter engine: execute_incdec: L%d O%d S%d", fop->op.assign.level, fop->op.assign.offset, fop->op.assign.size);
   
   /* 
    * point to the right base.
    */
   switch (fop->op.assign.level) {
      case 2:
         base = po->L2.header;
         break;
      case 3:
         base = po->L3.header;
         break;
      case 4:
         base = po->L4.header;
         break;
      case 5:
         base = po->DATA.data;
         break;
      default:
         JIT_FAULT("unsupported inc/dec level [%d]", fop->op.assign.level);
         break;
   }

   /* 
    * inc/dec the value with the proper size.
    */
   switch (fop->op.assign.size) {
      case 1:
         if (fop->opcode == FOP_INC) 
            *(u_int8 *)(base + fop->op.assign.offset) += (fop->op.assign.value & 0xff);
         else
            *(u_int8 *)(base + fop->op.assign.offset) -= (fop->op.assign.value & 0xff);
         break;
      case 2:
         if (fop->opcode == FOP_INC) 
            *(u_int16 *)(base + fop->op.assign.offset) += ntohs(fop->op.assign.value & 0xffff); 
         else
            *(u_int16 *)(base + fop->op.assign.offset) -= ntohs(fop->op.assign.value & 0xffff); 
         break;
      case 4:
         if (fop->opcode == FOP_INC) 
            *(u_int32 *)(base + fop->op.assign.offset) += ntohl(fop->op.assign.value & 0xffffffff);
         else
            *(u_int32 *)(base + fop->op.assign.offset) -= ntohl(fop->op.assign.value & 0xffffffff);
         break;
      default:
         JIT_FAULT("unsupported inc/dec size [%d]", fop->op.assign.size);
         break;
   }
      
   /* mark the packet as modified */
   po->flags |= PO_MODIFIED;

   return FLAG_TRUE;
}
Beispiel #11
0
/* 
 * execute a test.
 * return FLAG_TRUE if the test was successful
 */
static int execute_test(struct filter_op *fop, struct packet_object *po)
{
   /* initialize to the beginning of the packet */
   u_char *base = po->L2.header;
   int (*cmp_func)(u_int32, u_int32) = &cmp_eq;

   /* 
    * point to the right base.
    * if the test is L3.ttl, we have to start from
    * L3.header to count for offset.
    */
   switch (fop->op.test.level) {
      case 2:
         base = po->L2.header;
         break;
      case 3:
         base = po->L3.header;
         break;
      case 4:
         base = po->L4.header;
         break;
      case 5:
         base = po->DATA.data;
         break;
      case 6:
         base = po->DATA.disp_data;
         break;
      default:
         JIT_FAULT("unsupported test level [%d]", fop->op.test.level);
         break;
   }

   /* set the pointer to the comparison function */
   switch(fop->op.test.op) {
      case FTEST_EQ:
         cmp_func = &cmp_eq;
         break;
      case FTEST_NEQ:
         cmp_func = &cmp_neq;
         break;
      case FTEST_LT:
         cmp_func = &cmp_lt;
         break;
      case FTEST_GT:
         cmp_func = &cmp_gt;
         break;
      case FTEST_LEQ:
         cmp_func = &cmp_leq;
         break;
      case FTEST_GEQ:
         cmp_func = &cmp_geq;
         break;
      default:
         JIT_FAULT("unsupported test operation");
         break;
           
   }
   
   /* 
    * get the value with the proper size.
    * 0 is a special case for strings (even binary) 
    */
   switch (fop->op.test.size) {
      case 0:
         /* string comparison */
         if (cmp_func(memcmp(base + fop->op.test.offset, fop->op.test.string, fop->op.test.slen), 0) )
            return FLAG_TRUE;
         break;
      case 1:
         /* char comparison */
         if (cmp_func(*(u_int8 *)(base + fop->op.test.offset), (fop->op.test.value & 0xff)) )
            return FLAG_TRUE;
         break;
      case 2:
         /* short int comparison */
         if (cmp_func(htons(*(u_int16 *)(base + fop->op.test.offset)), (fop->op.test.value & 0xffff)) )
            return FLAG_TRUE;
         break;
      case 4:
         /* int comparison */
         if (cmp_func(htonl(*(u_int32 *)(base + fop->op.test.offset)), (fop->op.test.value & 0xffffffff)) )
            return FLAG_TRUE;
         break;
      default:
         JIT_FAULT("unsupported test size [%d]", fop->op.test.size);
         break;
   }
         
   return FLAG_FALSE;
}
Beispiel #12
0
/* 
 * execute a function.
 * return FLAG_TRUE if the function was successful
 */
static int execute_func(struct filter_op *fop, struct packet_object *po)
{
   switch (fop->op.func.op) {
      case FFUNC_SEARCH:
         /* search the string */
         if (func_search(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      case FFUNC_REGEX:
         /* search the string with a regex */
         if (func_regex(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      case FFUNC_PCRE:
         /* evaluate a perl regex */
         if (func_pcre(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;

      case FFUNC_REPLACE:
         /* replace the string */
         if (func_replace(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      case FFUNC_INJECT:
         /* replace the string */
         if (func_inject(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      case FFUNC_LOG:
         /* log the packet */
         if (func_log(fop, po) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      case FFUNC_DROP:
         /* drop the packet */
         func_drop(po);
         return FLAG_TRUE;
         break;
         
      case FFUNC_KILL:
         /* kill the connection */
         func_kill(po);
         return FLAG_TRUE;
         break;
         
      case FFUNC_MSG:
         /* display the message to the user */
         USER_MSG("%s", fop->op.func.string);
         return FLAG_TRUE;
         break;
         
      case FFUNC_EXEC:
         /* execute the command */
         if (func_exec(fop) == ESUCCESS)
            return FLAG_TRUE;
         break;
         
      default:
         JIT_FAULT("unsupported function [%d]", fop->op.func.op);
         break;
   }

   return FLAG_FALSE;
}
Beispiel #13
0
/*
 * evaluate a perl regex and return TRUE if found
 */
static int func_pcre(struct filter_op *fop, struct packet_object *po)
{
#ifndef HAVE_PCRE
   JIT_FAULT("pcre_regex support not compiled in ettercap");
   return -ENOTFOUND;
#else
   int ovec[PCRE_OVEC_SIZE];
   int ret;
   
   DEBUG_MSG("filter engine: func_pcre");
   
   memset(&ovec, 0, sizeof(ovec));
   
   switch (fop->op.func.level) {
      case 5:
         
         /* search in the real packet */
         if ( (ret = pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.data, po->DATA.len, 0, 0, ovec, sizeof(ovec) / sizeof(*ovec))) < 0)
            return -ENOTFOUND;

         /* the pcre wants to modify the packet */
         if (fop->op.func.replace) {
            u_char *replaced;
            u_char *q = fop->op.func.replace;
            size_t i, slen = 0;

            /* don't modify if in unoffensive mode */
            if (GBL_OPTIONS->unoffensive)
               JIT_FAULT("Cannot modify packets in unoffensive mode");
             
            /* 
             * worst case: the resulting string will need:
             *   (n * |input|) + |subst| bytes
             * where
             *   |input| is the length of the matched input string (not the regex!)
             *   |subst| is the length of the substition string
             *   n       is the number of replacement markers in subst
             *
             * therefore, we need to count the number of $ characters first
             * to get an upper limit of the buffer space needed
             */
            int markers = 0;
            for (i=0; q[i]; i++) {
               if (q[i] == '$') markers++;
            }
            /* now: i = strlen(q) */

            SAFE_CALLOC(replaced, markers*(ovec[1]-ovec[0]) + i + 1, sizeof(char));
          
            po->flags |= PO_MODIFIED;

            /* make the replacement */
            uint8_t escaped = 0;
            for (i = 0; i < fop->op.func.rlen; i++) {
               /* we encounter an escape character (\), so the next character is to be taken literally */
               if (!escaped && q[i] == '\\') {
                  escaped = 1;
               }
               /* there is an unescaped position marker */
               else if (!escaped && q[i] == '$') {
                  /* a marker is succeeded by an integer, make sure it is there */
                  if (q[i+1] == '\0')
                     JIT_FAULT("Incomplete marker at end of substitution string");

                  /* so now we can safely move on to the next character, our digit */
                  i++;
                  /* we only support up to 9 markers since we only parse a single digit */
                  if (q[i] < '0' || q[i] > '9')
                     JIT_FAULT("Incomplete marker without integer in substitution string");

                  int marker = q[i]-'0';

                  /* check if the requested marker was found in the pce */
                  if (marker > ret - 1 || marker == 0)
                     JIT_FAULT("Too many marker for this pcre expression");

                  int t = ovec[marker * 2];
                  int r = ovec[marker * 2 + 1];

                  /* copy the sub-string in place of the marker */
                  for ( ; t < r; t++) 
                     replaced[slen++] = po->DATA.data[t];

               }
               /* anything else either has no special meaning or is escaped,
                * so we just copy it
                */
               else {
                  replaced[slen++] = q[i];
                  escaped = 0;
               }
            }
            
            /* calculate the delta */
            int delta = (ovec[0]-ovec[1])+slen;

            /* check if we are overflowing pcap buffer */
            BUG_IF(po->DATA.data < po->packet);
            BUG_IF((u_int16)(GBL_PCAP->snaplen - (po->DATA.data - po->packet)) <= po->DATA.len+delta);

            /* if the substitution string has a different length than the
             * matched original string, we have to move around some data
             */
            int size_left = po->DATA.len - ovec[0] - slen;
            int data_left = po->DATA.len - ovec[1];
            DEBUG_MSG("func_pcre: match from %d to %d, substitution length is %d\n", ovec[0], ovec[1], slen);
            DEBUG_MSG("func_pcre: packet size changed by %d bytes\n", delta);
            if (delta != 0) {
               /* copy everything behind the matched string to the new position */
               memcpy(po->DATA.data+ovec[0]+slen, po->DATA.data + ovec[1], size_left < data_left ? size_left : data_left);
            }

            /* copy the modified buffer on the original packet */
            memcpy(po->DATA.data+ovec[0], replaced, slen);

            po->DATA.delta += delta;
            po->DATA.len += delta;

            SAFE_FREE(replaced);
         }
         
         break;
      case 6:
         /* search in the decoded one */
         if ( pcre_exec(fop->op.func.ropt->pregex, fop->op.func.ropt->preg_extra, po->DATA.disp_data, po->DATA.disp_len, 0, 0, NULL, 0) < 0)
            return -ENOTFOUND;
         break;
      default:
         JIT_FAULT("unsupported pcre_regex level [%d]", fop->op.func.level);
         break;
   }

   return ESUCCESS;
#endif
}