Leia a pilha de outro processo?

14

Estou tentando ler a pilha de um processo filho, mas sem sorte. Eu sei que é possível usar ptrace , mas a interface ptrace permite que você leia apenas uma palavra por vez, e eu estou tentando verificar uma parte maior da pilha.

Eu também tentei ler o /proc/$pid/mem dos limites da pilha como extraído do arquivo /proc/$pid/maps depois de usar o ptrace para anexá-lo (como sugerido aqui ) mas a leitura continua falhando (mesmo quando executada como root), embora o mesmo código tenha sucesso ao tentar ler de diferentes partes do processo (por exemplo, heap).

O que estou fazendo de errado? Existe alguma outra opção?

    
por user4537 20.02.2011 / 12:52

5 respostas

4

ptrace's interface allows you to read only one word at a time, and I'm trying to scan a larger portions of the stack

Bem, apenas use um loop, então. Eu sinceramente não vejo como isso constitui um problema com ptrace , eu uso o tempo todo para acessar processos remotamente.

Eu uso algo assim:

static int memcpy_from_target(pid_t pid, char *dest, long src, size_t n)
{
    static int const align = sizeof(long) - 1;

    while (n)
    {
        size_t todo = MIN(n, sizeof(long) - (src & align));
        long data = ptrace(PTRACE_PEEKTEXT, pid, src - (src & align), 0);
        if (errno)
        {
            perror("ptrace_peektext (memcpy_from_target)");
            return -1;
        }
        memcpy(dest, (char *)&data + (src & align), todo);

        dest += todo; src += todo; n -= todo;
    }

    return 0;
}
    
por 11.03.2011 / 13:51
1

Aqui está outra estratégia que pode precisar de ajustes, mas deve ser mais eficiente com grandes blocos de dados. A idéia é executar syscalls no processo remoto para recuperar o conteúdo da pilha. Ele precisará de um código de arquitetura específico, mas se você apenas segmentar x86 / x86_64, isso não deve ser muito trabalhoso.

  1. Crie um canal nomeado como "/tmp/fifo" em seu processo de chamada.
  2. Entre no processo rastreado até que ele retorne de um syscall, usando PTRACE_SYSCALL para a etapa, waitpid() para aguardar e PTRACE_GETREGS / PTRACE_PEEKTEXT para verificar o opcode atualmente executado.
  3. Faça o backup dos registros do processo remoto e de uma pequena área de sua pilha.
  4. Execute syscalls no processo remoto substituindo sua pilha pelos seus próprios dados: open("/tmp/fifo") , write() o conteúdo da pilha, close() o descritor.
  5. Restaurar o estado do processo remoto.
  6. Leia os dados do fifo do seu processo de chamada.

Pode haver alternativas mais elegantes para o pipe nomeado, mas não consigo pensar em nenhum agora. O motivo pelo qual eu uso apenas o syscalls é porque a injeção remota de código não é confiável nos sistemas modernos devido a várias proteções de segurança. A desvantagem é que ele irá travar até que o processo remoto faça um syscall (o que pode ser um problema para alguns programas que fazem principalmente cálculos).

Você pode ver um código gratuito implementando a maior parte do trabalho em este arquivo de origem . Comentários sobre o código são bem vindos!

    
por 13.03.2011 / 16:12
1

Você pode ler facilmente a pilha de outro processo usando o sistema de arquivos proc (você precisará de acesso root para isso). Antes de ler arbitrariamente a partir do / proc / pid / mem você precisa consultar o / proc / pid / maps. Uma simples leitura neste arquivo mostra muitas entradas. Estamos interessados na entrada marcada como pilha. Depois de conseguir isso, você precisa ler os limites inferior e superior da pilha. Agora simplesmente abra o arquivo / proc / pid / mem, procure o limite inferior da pilha e leia o tamanho correto dos dados. Espero que isso ajude.

    
por 26.07.2016 / 14:55
0

Outra sugestão.

Quando / se for aceito na árvore principal do kernel do Linux, você poderá usar a Cross Memory do Christopher Yeoh. Anexar patch. Veja a documentação para process_vm_readv , por exemplo.

    
por 04.11.2011 / 23:24
0

Você pode tentar lsstack . Ele usa o ptrace, assim como qualquer outro programa bem-sucedido "leia o processo de outro processo". Eu não consegui obter um programa usando a leitura / proc / $ pid / mem para funcionar. Eu acredito que você não pode fazer dessa maneira, embora, logicamente, você deva.

    
por 05.11.2011 / 00:25