Quando o kernel executa um processo, ele copia os argumentos da linha de comando para a memória de leitura / gravação pertencente ao processo (na pilha, pelo menos no Linux). O processo pode gravar nessa memória como qualquer outra memória. Quando ps
exibe o argumento, ele lê o que está armazenado naquele endereço específico na memória do processo. A maioria dos programas mantém os argumentos originais, mas é possível alterá-los. A descrição POSIX de ps
afirma que
It is unspecified whether the string represented is a version of the argument list as it was passed to the command when it started, or is a version of the arguments as they may have been modified by the application. Applications cannot depend on being able to modify their argument list and having that modification be reflected in the output of ps.
A razão pela qual isso é mencionado é que a maioria das variantes unix refletem a mudança, mas as implementações POSIX em outros tipos de sistemas operacionais não.
Esse recurso é de uso limitado porque o processo não pode fazer alterações arbitrárias. No mínimo, o comprimento total dos argumentos não pode ser aumentado, porque o programa não pode alterar a localização em que ps
buscará os argumentos e não poderá estender a área além de seu tamanho original. O comprimento pode efetivamente ser diminuído colocando-se bytes nulos no final, porque os argumentos são strings com terminação nula no estilo C (isto é indistinguível de ter um monte de argumentos vazios no final).
Se você realmente quer cavar, pode ver a fonte de uma implementação de código aberto. No Linux, a fonte de ps
não é interessante, tudo o que você verá é que lê os argumentos da linha de comando do sistema de arquivos proc , em /proc/PID/cmdline
. O código que gera o conteúdo deste arquivo está no kernel, em proc_pid_cmdline_read
em fs/proc/base.c
. A parte da memória do processo (acessada com access_remote_vm
) vai do endereço mm->arg_start
a mm->arg_end
; esses endereços são registrados no kernel quando o processo é iniciado e não podem ser alterados posteriormente.
Alguns daemons usam essa capacidade para refletir seu status, por exemplo, eles alteram seu argv[1]
para uma string como starting
ou available
ou exiting
. Muitas variantes unix têm uma função setproctitle
para fazer isso. Alguns programas usam essa capacidade para ocultar dados confidenciais. Observe que isso é de uso limitado, pois os argumentos da linha de comando ficam visíveis enquanto o processo é iniciado.
A maioria dos idiomas de alto nível copia os argumentos para objetos de string e não permite modificar o armazenamento original. Aqui está um programa em C que demonstra essa habilidade, alterando argv
elementos diretamente.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
system("ps -p $PPID -o args=");
for (i = 0; i < argc; i++)
{
memset(argv[i], '0' + (i % 10), strlen(argv[i]));
}
system("ps -p $PPID -o args=");
return 0;
}
Exemplo de saída:
./a.out hello world
0000000 11111 22222
Você pode ver a modificação de argv
no código-fonte da onda. O Curl define uma função cleanarg
em src/tool_paramhlp.c
que é usada para alterar um argumento para todos os espaços usando memset
. Em src/tool_getparam.c
esta função é usada algumas vezes, e. redigindo a senha do usuário . Como a função é chamada a partir da análise de parâmetros, isso acontece no início de uma chamada de curl, mas descarregar a linha de comando antes que isso aconteça ainda mostrará todas as senhas.
Como os argumentos são armazenados na própria memória do processo, eles não podem ser alterados a partir do exterior, exceto pelo uso de um depurador.