Lire la stack d'un autre process?

J'essaie de lire la stack d'un process enfant mais pas de chance. Je sais que c'est possible en utilisant ptrace , mais l'interface de ptrace vous permet de lire un seul mot à la fois, et j'essaie de scanner une plus grande partie de la stack.

J'ai aussi essayé de lire le /proc/$pid/mem des limites de la stack comme extrait du /proc/$pid/maps après avoir utilisé ptrace pour l'attacher (comme suggéré ici ) mais la lecture continue d'échouer (même en cours d'exécution en tant que root) bien que le même code réussisse lors de la lecture de différentes parties du process (par exemple tas).

Qu'est-ce que je fais mal? Y a-t-il une autre option?

L'interface de ptrace vous permet de ne lire qu'un seul mot à la fois, et j'essaie de scanner une plus grande partie de la stack

Eh bien, il suffit d'utiliser une boucle, alors. Honnêtement, je ne vois pas comment cela constitue un problème avec ptrace , je l'utilise tout le time pour accéder à distance aux process.

J'utilise quelque chose comme ça:

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

Voici une autre stratégie qui pourrait nécessiter des ajustements, mais devrait être plus efficace avec de gros blocs de données. L'idée est d'exécuter syscalls dans le process distant afin de récupérer le contenu de la stack. Il aura besoin d'un code d'architecture spécifique, mais si vous ne ciblez que x86 / x86_64, il ne devrait pas être trop compliqué.

  1. Créez un canal nommé tel que "/tmp/fifo" dans votre process d'appel.
  2. Entrez dans le process tracé jusqu'à ce qu'il revienne d'un appel syscall, en utilisant PTRACE_SYSCALL à l'étape, waitpid() pour attendre et PTRACE_GETREGS / PTRACE_PEEKTEXT pour vérifier l'opcode en cours d'exécution.
  3. Sauvegardez les registres du process distant et une petite zone de sa stack.
  4. Exécutez syscalls sur le process distant en écrasant sa stack avec vos propres données: open("/tmp/fifo") , write() le contenu de la stack, close() le descripteur.
  5. Restaurez l'état du process distant.
  6. Lisez datatables fifo de votre process d'appel.

Il pourrait y avoir des alternatives plus élégantes à la pipe nommée, mais je ne peux pas penser à aucun droit maintenant. La raison pour laquelle j'utilise uniquement syscalls est parce que l'injection de code à distance est assez peu fiable sur les systèmes modernes en raison de diverses protections de security. L'inconvénient est qu'il va se bloquer jusqu'à ce que le process distant fasse un syscall (ce qui peut être un problème pour certains programmes qui font principalement des calculs).

Vous pouvez voir un code libre implémentant la plupart du travail dans ce file source . Les commentaires sur le code sont les bienvenus!

Vous pouvez facilement lire la stack d'un autre process en utilisant le système de files proc (vous aurez besoin d'un access root pour cela). Avant de lire arbitrairement le file / proc / pid / mem, vous devez consulter le file / proc / pid / maps. Une simple lecture dans ce file montre beaucoup d'inputs. Nous sums intéressés par l'input marquée comme stack. Une fois que vous obtenez cela, vous devez lire les limites inférieure et supérieure de la stack. Maintenant, ouvrez simplement le file / proc / pid / mem, searchz la limite inférieure de la stack et lisez la taille correcte des données. J'espère que ça aide.

Une autre suggestion.

Quand / si elle est acceptée dans l'arborescence du kernel Linux principal, vous pourrez utiliser le patch Cross Memory Attach de Christopher Yeoh. Consultez la documentation de process_vm_readv par exemple.

Vous pouvez essayer lsstack . Il utilise ptrace, comme tout autre programme de "lecture de la stack d'un autre process". Je ne pouvais pas get un programme en utilisant la lecture / proc / $ pid / mem pour fonctionner. Je crois que vous ne pouvez pas le faire de cette façon, bien que, logiquement, vous devriez le faire.