quão importante é hoje em dia garantir que todas as minhas DLLs tenham endereços de base não conflitantes?

Raymond

20 de janeiro, 2017

Voltar no dia, uma das coisas que foram exortados a fazer foi alterar a base de suas DLLs de modo que todos eles tinham nonoverlapping intervalos de endereços, evitando, assim, o custo de tempo de execução do internamento. Isso ainda é importante hoje em dia?

esta situação é outra demonstração de como é importante que um bom conselho venha com uma lógica para que você possa dizer quando se torna um mau conselho.

a justificativa para o rebasing é assim: se uma DLL é carregada em seu endereço base preferido, a imagem pode ser paginada diretamente do backing store sem exigir nenhuma correção. Isso significa que as páginas podem ser compartilhadas entre processos, pois cada processo recebe uma cópia idêntica. (Claro, o compartilhamento pára quando alguém escreve na página e torna sua cópia diferente da cópia compartilhada.)

se uma DLL não puder ser carregada em seu endereço preferido, a imagem será realocada e toda a DLL realocada agora será suportada pelo Arquivo de página.1 Esta é uma operação relativamente cara, uma vez que a DLL deve ser lida a partir do disco e Corrigida, e uma taxa de confirmação para o arquivo de página é incorrida para garantir que haja espaço para gravar as páginas fixas. Além disso, se dois processos realocam a DLL e acontecem por alguma coincidência para realocá-los para o mesmo lugar, O Windows NT não tenta compartilhar as imagens realocadas. Haverá várias cópias no arquivo da página.

o custo dessa realocação dinâmica é o que o rebasing tenta evitar. Vamos chamar isso de ” penalidade de realocação.”

digite ASLR.

ASLR faz com que as DLLs sejam carregadas em endereços pseudo-aleatórios. Consequentemente, uma DLL será carregada em seu endereço base preferido apenas no caso de uma coincidência surpreendente.

Ok, então vamos voltar ao raciocínio para ver se ele ainda se aplica.

uma DLL sendo carregada longe de seu endereço base preferido incorre em uma penalidade de realocação? Se você pensar sobre isso, ASLR significa que nenhuma DLL carrega em seu endereço preferido, mas também vimos que o kernel faz acomodações para isso, de modo que DLLs submetidas ao ASLR ainda possam compartilhar páginas, e o faz sem forçar toda a DLL a ser realocada na carga inicial. Portanto, não há penalidade de realocação no caso em que a DLL foi realocada pela ASLR.

mas e se a DLL for realocada por algum outro motivo? Por exemplo, pode ser que o endereço base escolhido pelo ASLR não esteja disponível no processo, porque o processo já alocou outra coisa nesse local. Nesse caso, uma realocação tradicional deve ocorrer e você paga a penalidade de realocação.

Ah, mas aqui está a coisa: quando uma DLL é carregada, ASLR atribuirá um endereço base aleatoriamente entre os endereços base disponíveis que ainda não estão sendo usados.2 portanto, você não entrará no cenário “o endereço base escolhido pelo ASLR não está disponível” porque o ASLR escolhe o endereço base da DLL entre o endereço base disponível.3

Ok, então você ainda pode entrar em uma situação de conflito, mas você tem que realmente trabalhar nisso. Por exemplo, você pode carregar uma DLL em um processo e obter um endereço base atribuído pelo ASLR. Em seguida, inicie um segundo processo, aloque intencionalmente a memória nesse endereço (para forçar a colisão) e carregue a DLL. Nesse caso, haverá uma realocação porque você se agachou no local onde a ASLR queria colocar a DLL. Mas isso não é pior do que o que você tinha antes do ASLR: no mundo pré-ASLR, agachar o endereço base preferido de uma DLL teria forçado uma penalidade de realocação de qualquer maneira.

então, vamos ver qual é a história. Para rebase ou não para rebase?

na presença de ASLR, rebasing suas DLLs não tem efeito porque ASLR vai ignorar seu endereço base de qualquer maneira e realocar a DLL em um local de sua escolha pseudo-aleatória.

lembre-se, mesmo que o rebasing não tenha efeito, também não faz mal.

se você estiver em um sistema sem ASLR (seja porque é anterior ao ASLR ou porque o ASLR foi desativado por qualquer motivo), o rebasing ajudará, pelas razões tradicionais.

lembre-se, sistemas sem ASLR são realmente difíceis de encontrar hoje em dia, então o rebasing não oferece nenhum benefício na esmagadora maioria dos casos. Mas naquela porcentagem cada vez menor de casos em que você não tem ASLR, o rebasing ajuda.

conclusão: não faz mal rebase, apenas no caso, mas entenda que a recompensa será extremamente rara. Construa sua DLL com /DYNAMICBASE habilitado (e com /HIGHENTROPYVA para uma boa medida) e deixe a ASLR fazer o trabalho de garantir que nenhuma colisão de endereço base ocorra. Isso cobrirá praticamente todos os cenários do mundo real. Se acontecer de você cair em um dos casos muito raros em que o ASLR não está disponível, seu programa ainda funcionará. Pode correr um pouco mais devagar devido à penalidade de realocação.

1 mais precisamente, todas as páginas que continham correções são colocadas no arquivo de página. Discutimos este ponto mais fino da última vez.

2 Ok, há um terceiro caso, que é onde ASLR simplesmente ficou sem endereços de base. Mas, novamente, isso não é pior do que o que você tinha antes do ASLR: se você ficar sem endereços básicos, então é todo homem por si mesmo. Cada vez que uma nova DLL é carregada, o kernel precisa percorrer um pedaço grande de espaço de endereço disponível para carregar a DLL.

3 como resultado, o ASLR realmente faz um trabalho melhor ao evitar colisões do que o rebasing manual, uma vez que o ASLR pode visualizar o sistema como um todo, enquanto o rebasing manual requer que você conheça todas as DLLs que são carregadas em seu processo e a coordenação de endereços de base em vários fornecedores geralmente não é possível.

Raymond Chen

Siga

Leave a Reply