2014-02-03 2 views
0

У меня есть небольшой код C, который сбрасывает память процесса, а затем пытается привязать REGEX к строке. Все идет хорошо, если я хочу сбрасывать процесс, но REGEX терпит неудачу, или я неправильно искал буфер памяти. Есть идеи?Linux C область памяти процесса сброса и поиск строки проблемы

#define _LARGEFILE64_SOURCE 

#include <stdlib.h> 
#include <stdio.h> 
#include <sys/ptrace.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <regex.h> 

void dump_region(int fd, off64_t start, off64_t end) 
{ 
     char buf[4096]; 
     int a, i; 
     regex_t re; 
     regmatch_t pm; 

     a = regcomp(&re, "([0-9]{10,20})", REG_EXTENDED); 

     if(a!=0) 
      printf(" -> Error: Invalid Regex"); 

     lseek64(fd, start, SEEK_SET); 
     while(start < end) { 
     int rd; 

     rd = read(fd, buf, 4096); 
     //write(STDOUT_FILENO, buf, rd); // HERE dumping is OK 
     a = regexec(&re, &buf[0], 1, &pm, REG_EXTENDED); // something I do wrong here 
     if(a==0) { 
      for(i = pm.rm_so; i < pm.rm_eo; i++) 
       printf("%c", buf[i]); 
       printf("\n"); 
     } 
     start += 4096; 
     } 
} 

int main(int argc, char *argv[]) 
{ 
     FILE *maps; 
     int mem; 
     pid_t pid; 
     char path[BUFSIZ]; 

     if(argc < 2) { 
     fprintf(stderr, "usage: %s pid\n", argv[0]); 
     return EXIT_FAILURE; 
     } 

     pid = strtol(argv[1], NULL, 10); 
     if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) { 
     perror("ptrace"); 
     return EXIT_FAILURE; 
     } 

     snprintf(path, sizeof(path), "/proc/%d/maps", pid); 
     maps = fopen(path, "r"); 

     snprintf(path, sizeof(path), "/proc/%d/mem", pid); 
     mem = open(path, O_RDONLY); 

     if(maps && mem != -1) { 
     char buf[BUFSIZ + 1]; 

     while(fgets(buf, BUFSIZ, maps)) { 
       off64_t start, end; 

       sscanf(buf, "%llx-%llx", &start, &end); 
       dump_region(mem, start, end); 
     } 
     } 

     ptrace(PTRACE_DETACH, pid, NULL, NULL); 
     if(mem != -1) 
     close(mem); 
     if(maps) 
     fclose(maps); 

     return EXIT_SUCCESS; 
} 

EDIT:

Пробовал другой вариант, еще что-то пойдет не так или что-то я просто скучаю ...

#define _LARGEFILE64_SOURCE 

#include <stdlib.h> 
#include <stdio.h> 
#include <sys/ptrace.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <regex.h> 

void dump_region(int fd, off64_t start, off64_t end) 
{ 
     char buf[4096]; 
     int status,i; 
     int cflags = REG_EXTENDED; 
     regmatch_t pmatch[1]; 
     const size_t nmatch=1; 
     regex_t reg; 
     const char *pattern="([0-9]{10,20})"; 

     regcomp(&reg, pattern, cflags); 

     lseek64(fd, start, SEEK_SET); 
     while(start < end) { 
       int rd; 

       rd = read(fd, buf, sizeof buf - 1); 
       if(rd > 0) 
       { 
        buf[rd] = '\0'; 
        status = regexec(&reg, buf, nmatch, pmatch, 0); 
        if(status == REG_NOMATCH) 
         printf("No Match\n"); 
        else if(status == 0){ 
         printf("Match:\n"); 
         for (i=pmatch[0].rm_so; i<pmatch[0].rm_eo; ++i) { 
           putchar(buf[i]); 
         } 
         printf("\n"); 
        } 
        regfree(&reg); 
        return; 
       } 
       start += 4096; 
     } 
} 

int main(int argc, char *argv[]) 
{ 
     FILE *maps; 
     int mem; 
     pid_t pid; 
     char path[BUFSIZ]; 

     if(argc < 2) { 
       fprintf(stderr, "usage: %s pid\n", argv[0]); 
       return EXIT_FAILURE; 
     } 

     pid = strtol(argv[1], NULL, 10); 
     if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) { 
       perror("ptrace"); 
       return EXIT_FAILURE; 
     } 

     snprintf(path, sizeof(path), "/proc/%d/maps", pid); 
     maps = fopen(path, "r"); 

     snprintf(path, sizeof(path), "/proc/%d/mem", pid); 
     mem = open(path, O_RDONLY); 

     if(maps && mem != -1) { 
       char buf[BUFSIZ + 1]; 

       while(fgets(buf, BUFSIZ, maps)) { 
         off64_t start, end; 

         sscanf(buf, "%llx-%llx", &start, &end); 
         dump_region(mem, start, end); 
       } 
     } 

     ptrace(PTRACE_DETACH, pid, NULL, NULL); 
     if(mem != -1) 
       close(mem); 
     if(maps) 
       fclose(maps); 

     return EXIT_SUCCESS; 
} 

Любая помощь? Идея?

ОБНОВЛЕНИЕ. Кажется, что вторая версия работает частично, но примерно от 1193 совпадений, которые я получаю с egrep из файла сбрасываемой памяти, я получаю только два кода с моим кодом. Есть идеи?

+0

Я не знаю много о regexp в C, но не должен '& buf [0]' быть просто '& buf', чтобы дать ссылку на начало буфера? – Aif

+1

Дамп в файл, запустите 'файл строк | egrep 'ваше регулярное выражение'. Это нашло? Если это так, регулярное выражение является правильным, а бит, который вам не хватает, - это извлечение c-строки (как предложено в ответе от разговора) – Useless

+0

Да, я сделал это, использовал тот же код, но сбрасывал в файл, а затем использовал строки с точным REGEX и обнаружил много матчей. – bsteo

ответ

1

Нет гарантий, что буфер, который вы передаете regexec(), является допустимой строкой, которая должна быть. The manual page for regexec() описывает функцию:

regexec() используется для сопоставления с завершающим нулем строку с скомпилированных шаблонов буфера [...]

Таким образом, вы должны убедиться, что данные, искавшие является собственно строка, делая что-то вроде:

rd = read(fd, buf, sizeof buf - 1); 
if(rd > 0) 
{ 
    buf[rd] = '\0'; 
    a = regexec(&re, buf, 1, &pm, REG_EXTENDED); 
    /* ... rest of code ... */ 
} 

Это также защищает от ошибок чтения, когда rd будет < 0.

Как правило, понимаете, что «потоковая передача» регулярного выражения не является вообще тривиальной; что, если соответствие RE соответствует размеру вашего буфера чтения? Тогда вы рискуете потерять совпадение, поскольку вы разрешаете совпадению видеть непересекающиеся «окна» в фактические данные.

Furter, как указано в комментарии @xtmtrx's, данные, которые вы читаете, не являются текстовыми, это двоичные. Это означает, что он часто содержит множество «странных» значений, например встроенных 0-байтов, которые будут выглядеть (до regexec()) в качестве ограничителей строк. Если один из них появится перед некоторыми данными, которые вы ищете в одном блоке, вы пропустите данные, так как regexec() не будет читать после конца строки.

Одно из решений заключается в отфильтровывании нетекстовых данных перед попыткой сопоставления, например, с использованием цикла и isprint().

+0

О, позвольте мне попробовать ... – bsteo

+0

Все еще что-то не так. Если я сброшу память процесса в STDOUT и отправлю в файл с помощью 'write (STDOUT_FILENO, buf, rd)' я могу grep для '" ([0-9] {10,20}) "и найти много совпадений, но с моим код не соответствует, даже работает код REGEX. – bsteo

+1

Может быть, потому, что сбрасываемая память - это данные RAW, а не только текст? – bsteo

Смежные вопросы