Há uma observação interessante no artigo Process Security and Access Rights do MSDN:
... se o processo A tiver um identificador para processar B com acesso PROCESS_DUP_HANDLE , ele poderá duplicar o pseudo identificador para o processo B. Isso cria um identificador que tem acesso máximo ao processo B.
Se você traduzir isso livremente para o russo, aqui diz que, tendo um descritor para um processo com o acesso PROCESS_DUP_HANDLE certo, podemos, usando a função DuplicateHandle (...) , obter um descritor com as máscaras de acesso máximas permitidas para esse processo.

Demonstração
O código-fonte que explora esse recurso é bastante simples:
#include <Windows.h> int wmain(int argc, PWSTR argv[]) { HANDLE ProcessAllAccessHandle; HANDLE ProcessDuplicateHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, _wtoi(argv[1])); if (ProcessDuplicateHandle) { if (DuplicateHandle(ProcessDuplicateHandle, GetCurrentProcess(), GetCurrentProcess(), &ProcessAllAccessHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { CloseHandle(ProcessAllAccessHandle); } CloseHandle(ProcessDuplicateHandle); } return 0; }
Como resultado da compilação e vinculação, obtemos um utilitário de teste que usa o identificador de processo de destino (PID) como argumento. Em seguida, o utilitário abre o processo especificado com o PROCESS_DUP_HANDLE à direita. Assim, simulamos a condição necessária para a disponibilidade de um descritor para um processo com o PROCESS_DUP_HANDLE correto (== 0x40).
Como demonstração, rastreio o utilitário montado no WinDbg:
0:000> lsa @$ip 0,3 > 13: if (ProcessDuplicateHandle) 14: { 15: if (DuplicateHandle(ProcessDuplicateHandle, 0:000> !handle @@C++(ProcessDuplicateHandle) 3 Handle 80 Type Process Attributes 0 GrantedAccess 0x40: None DupHandle HandleCount 9 PointerCount 260518
E então movimento do pulso Ao chamar DuplicateHandle (...), obtemos o segundo descritor para o mesmo processo, mas com as permissões mais amplas:
0:000> lsa @$ip 0,3 > 23: CloseHandle(ProcessAllAccessHandle); 24: } 25: CloseHandle(ProcessDuplicateHandle); 0:000> !handle @@C++(ProcessAllAccessHandle) 3 Handle 84 Type Process Attributes 0 GrantedAccess 0x1fffff: Delete,ReadControl,WriteDac,WriteOwner,Synch Terminate,CreateThread,,VMOp,VMRead,VMWrite,DupHandle,CreateProcess,SetQuota,SetInfo,QueryInfo,SetPort HandleCount 10 PointerCount 292877
O ponto principal é o valor GrantedAccess, que para o novo descritor é 0x1fffff, que corresponde a PROCESS_ALL_ACCESS . Infelizmente, o WinDbg não exibe o PID do processo de destino. Mas, para garantir que o descritor seja recebido pelo processo desejado, é possível examinar os descritores pelo Process Explorer (depois de especificar o PID especificado nos argumentos da linha de comando no depurador):
0:000> dx argv[1] argv[1] : 0x1b7c2e2412c : "21652" [Type: wchar_t *]

Na captura de tela, o utilitário abre os descritores para executar o notepad.exe.
Por que isso está acontecendo?
Primeiro, porque ao duplicar o descritor, se a máscara de acesso para o objeto não for expandida (e o sinalizador de operação DUPLICATE_SAME_ACCESS for especialmente especificado para nós), não há verificação de que o processo (no qual o descritor duplicado será criado) tenha acesso a esse objeto. Só é verificado se os descritores de processo passados para a função DuplicateHandle (...) possuem a máscara de acesso permitida PROCESS_DUP_HANDLE . E a cópia do descritor entre os processos ocorre sem verificar os direitos de acesso (repito: se o novo descritor tiver a máscara de direitos permitidos não maior que o descritor duplicado original).
E, em seguida, deve-se observar que a chamada para GetCurrentProcess () retorna uma constante, o mesmo pseudo-descritor (pseudo-identificador) mencionado no início desta publicação. Existem dois pseudo-descritores documentados com valores constantes que estão fisicamente ausentes na tabela de descritores de processos. Mas esses descritores são processados por todas as funções do kernel (junto com os descritores usuais da tabela de descritores de processos):
É o valor de NtCurrentProcess (== -1) que retorna a chamada GetCurrentProcess () .
Esse pseudo-descritor na estrutura de um processo específico significa um objeto desse processo com os direitos PROCESS_ALL_ACCESS (na verdade, existem nuances, mas o artigo não é sobre elas). Acontece que esse vínculo consigo mesmo, mas através do descritor:

Ou seja, nossa chamada para DuplicateHandle (ProcessDuplicateHandle, GetCurrentProcess (), ...) será interpretada da seguinte maneira: no processo aberto (destino), duplique o identificador com o valor -1. E para o processo de destino (aquele no qual temos o descritor armazenado na variável ProcessDuplicateHandle), o valor -1 se referirá a esse mesmo processo de destino com os direitos PROCESS_ALL_ACCESS . Portanto, como resultado, obtemos um descritor para o processo de destino com direitos máximos.
Em vez de um epílogo
Repito o pensamento escrito no início: se alguém recebe um descritor para o processo com o PROCESS_DUP_HANDLE certo, então, no modelo de segurança do Windows, ele poderá obter outro descritor para o mesmo processo, mas com os direitos PROCESS_ALL_ACCESS (e fazer o que bem entender com o processo )
Obrigado a todos que leram a publicação até o fim. Convido todos a participarem da pesquisa para descobrir como essas publicações podem ser interessantes / úteis para o público.