c - Linux C转储进程内存区域和搜索字符串问题

标签 c regex linux proc

我有一些 C 代码可以转储进程内存,然后尝试通过 REGEX 匹配字符串。如果我想转储进程但 REGEX 失败,或者我错误地搜索内存缓冲区,一切顺利。有什么想法吗?

#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;
}

编辑:

尝试了另一个版本,还是出问题了或者我只是想念的东西......

#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,我的代码只得到了两个。有什么想法吗?

最佳答案

无法保证您传递给 regexec() 的缓冲区是一个有效的字符串,应该是。 The manual page for regexec() 将该功能描述为:

regexec() is used to match a null-terminated string against the precompiled pattern buffer [...]

因此,您必须确保要搜索的数据是正确的字符串,方法如下:

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 匹配跨越了您的读取缓冲区大小怎么办?然后您可能会错过匹配,因为您只允许匹配器看到实际数据中不相交的“窗口”。

此外,正如 @xtmtrx's 中指出的那样评论,你正在阅读的数据不是文本,它是二进制的。这意味着它通常会包含很多“奇怪”的值,例如嵌入的 0 字节看起来(到 regexec() )作为字符串终止符。如果其中一个出现在您在一个 block 中查找的某些数据之前,您将错过自 regexec() 以来的数据。不会读取超过字符串的末尾。

一种解决方案是在尝试匹配之前过滤掉非文本数据,使用循环和 isprint() ,例如。

关于c - Linux C转储进程内存区域和搜索字符串问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21524914/

相关文章:

c - 在c中消隐一个char变量

php - 两个符号之间但不是该符号的三个之间的字符串的正则表达式

python - 设置 Gtk.ComboBoxText 默认项?

linux - Linux 上的 SVG 到 SWF?

linux - Linux 上的屏幕截图

c - 转换阶段 4 的非保留标识符是否会导致无法在转换阶段 7 保留文件范围标识符?

C:发送文件到套接字

arrays - 发生堆缓冲区溢出不确定是否在 C 中正确为二维数组分配内存

适用于英国移动设备的 Javascript 正则表达式

java - Java中如何用逗号和空格分割表达式?