COVIL HACKER

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » COVIL HACKER » Vulnerabilidades/exploração de software » Artigo Explorando o navegador Chrome, Parte 1: Introdução à V8 e ao Ja


Artigo Explorando o navegador Chrome, Parte 1: Introdução à V8 e ao Ja

Сообщений 1 страница 2 из 2

1

navegadores da Web, nosso vasto portal para a Internet. Hoje, os navegadores desempenham um papel vital nas organizações modernas, pois cada vez mais aplicativos de software são entregues aos usuários por meio de um navegador da Web como aplicativos da Web. Quase tudo o que você faz na Internet envolve o uso de um navegador da Web e, como resultado, os navegadores estão entre os produtos de software de consumo mais usados ​​no planeta.
Como porta de entrada para a Internet, os navegadores também apresentam riscos significativos à integridade dos dispositivos de computação pessoal. Agora ouvimos quase diariamente: " O bug do Google Chrome está sendo explorado ativamente como dia zero " ou " O Google confirma uma quarta exploração de dia zero no Chrome em 2022 ". Na verdade, as explorações do navegador não são novas, elas acontecem há muitos anos e a primeira exploração documentada de execução remota de código é CVE-1999-0280 . A primeira divulgação potencialmente pública de um exploit de navegador usado na natureza foi o exploit Aurora para o Internet Explorer, que afetou o Google em dezembro de 2010.
Meu interesse em navegadores da web surgiu em 2018, quando meu amigo Michael Weber me apresentou ao desenvolvimento ofensivo de extensões de navegador , o que realmente abriu meus olhos para uma possível superfície de ataque. Depois disso, comecei a me aprofundar nas partes internas do Chrome e fiquei muito interessado na exploração do navegador da web. Porque, sejamos honestos, qual Red Team não gostaria de uma exploração de "um clique" ou mesmo "sem clique" em um navegador da web?
Quando se trata de navegadores no mundo da pesquisa de segurança, eles são considerados um dos alvos mais impressionantes para encontrar vulnerabilidades. estudar as partes internas do navegador parece uma meta inatingível para muitos pesquisadores.
Independentemente disso, dei os passos para mergulhar na " Introdução ao Hard Target Internals " do maxpl0it , passando por um incrível curso de treinamento de órgãos". Que eu recomendo fortemente que você tome! Este curso me forneceu muitas informações básicas sobre o funcionamento interno e interno de navegadores como Chrome e Firefox. Depois disso, comecei a ler tudo o que pude, desde blogs do Chromium até postagens de desenvolvedores v8. Como meu método de ensino é mais do estilo "aprender, aprender, conhecer", estou publicando uma série de postagens de blog "Usando o navegador Chrome" para fornecer uma visão interna do navegador e aprender mais sobre como usar o navegador Chrome no Windows. profundidade, o tempo todo estudando eu mesmo.

Agora você deve estar me perguntando por que o Chrome e por que o Windows? Bom, dois motivos:A participação de mercado do Chrome é de cerca de 73%, tornando-o o navegador mais usado no mundo.
O Windows tem uma participação de mercado de cerca de 90%, tornando-o o sistema operacional mais usado no mundo.
Aprender a direcionar o software mais usado no mundo, como o Red Team, melhora muito nossas chances de encontrar bugs, escrever exploits e usá-los com sucesso em missões.

AVISO Devido à grande complexidade dos navegadores, mecanismos JavaScript e compiladores JIT, essas postagens de blog serão muito, muito difíceis de ler.
No momento, esta será uma série de três (3) postagens de blog. Mas, dependendo da complexidade e quantidade de informações abordadas, posso dividir o material em vários posts adicionais.
Observe - estou escrevendo essas postagens de blog enquanto estou aprendendo ao longo do caminho. Então, por favor, tenha paciência comigo, pois pode demorar um pouco para postar postagens subsequentes nesta série.
Ao mesmo tempo, se você perceber que cometi um erro em minhas postagens ou enganei o leitor, entre em contato comigo! Quaisquer recomendações, críticas construtivas, críticas, etc. também são muito bem vindas!
Em suma, ao final desta série de postagens de blog, teremos coberto tudo o que precisamos saber para começar a investigar e explorar os possíveis bugs do Chrome. Na última postagem desta série, tentaremos explorar CVE-2018-17463 , uma vulnerabilidade do compilador JIT no otimizador Chrome v8 (TurboFan) descoberta por Samuel Gross .
Então, sem mais delongas, vamos mergulhar no complexo mundo da exploração do navegador!
Na postagem do blog de hoje, examinaremos os principais conceitos preliminares que precisamos entender completamente antes de nos aprofundarmos. Serão discutidos os seguintes tópicos:
Fluxo do motor JavaScript
Pipeline do compilador do mecanismo JavaScript
Máquinas de pilha e registro
JavaScript e componentes internos do V8
representação de objeto
Classes ocultas (mapa)
Transições de forma (mapas)
Especificações
Elementos e matrizes
Ver objetos do Chrome na memória
Marcação de ponteiro
Compressão de ponteiro
Mas antes de começarmos, certifique-se de compilar v8 e d8 no Windows para acompanhar. você pode ler em meu artigo Construindo o Chrome V8 para Windows. Instruções detalhadas sobre como fazer isso,

Entendendo os mecanismos JavaScript
Começamos nossa jornada pelo funcionamento interno do navegador, primeiro entendendo o que são os mecanismos JavaScript e como eles funcionam. Os mecanismos JavaScript são essenciais para a execução do código JavaScript nos sistemas. Eles costumavam ser apenas intérpretes, mas hoje os mecanismos JavaScript modernos são programas complexos que incluem muitos componentes de aprimoramento de desempenho, como otimização de compiladores e compilação JIT.
Na verdade, muitos mecanismos JS diferentes são usados ​​hoje, por exemplo:
V8 é um mecanismo JavaScript e WebAssembly de código aberto e de alto desempenho do Google usado no Chrome.
SpiderMonkey é o JavaScript e WebAssembly Engine da Mozilla usado no Firefox.
Charka é um mecanismo JScript nativo desenvolvido pela Microsoft para uso no IE e no Edge.
JavaScriptCore é o mecanismo JavaScript integrado da Apple para usar o WebKit no Safari.
Então, por que precisamos desses mecanismos JavaScript e todas as suas complexidades?
Como sabemos, o JavaScript é uma linguagem de script leve, interpretada e orientada a objetos. Em linguagens interpretadas, o código é executado linha por linha e o resultado do código é retornado imediatamente, então não precisamos compilar o código para outro formulário antes que o navegador o execute. Isso geralmente não torna essas linguagens boas, devido a considerações de desempenho. Neste caso, estamos falando de uma compilação, como uma compilação Just-In-Time; onde o código JavaScript é analisado em bytecode (que é uma abstração do código de máquina) e, em seguida, JIT otimizado para tornar o código muito mais eficiente e, de certa forma, "rápido".
Agora, embora cada um dos mecanismos JavaScript acima possa ter diferentes compiladores e otimizadores, eles são amplamente projetados e implementados da mesma maneira com base no padrão EcmaScript (que também é usado de forma intercambiável com o JavaScript). A especificação EcmaScript detalha como o JavaScript deve ser implementado por um navegador para que um programa JavaScript funcione da mesma forma em todos os navegadores.
Então, o que realmente acontece depois que executamos o código JavaScript? Bem, para detalhar isso, forneci o diagrama abaixo, que mostra uma visão geral de alto nível do "fluxo" geral, também conhecido como o pipeline de compilação dos mecanismos JavaScript.

https://forumupload.ru/uploads/001b/c9/09/2/t223372.png

Pode parecer confuso no começo, mas não se preocupe - na verdade não é tão difícil de entender. Então, vamos detalhar o "fluxo" passo a passo e explicar o que cada um desses componentes faz.
Analisador : Depois de executar o código JavaScript, o código é passado para o mecanismo JavaScript e passamos para nossa primeira etapa, que é a análise do código. O analisador converte o código para o seguinte:
Tokens : O código é primeiro dividido em "tokens", como um identificador, um número, uma string, um operador, etc. Isso é conhecido como "análise léxica" ou "tokenização".
Exemplo: var num = 42 é dividido em var,num,=,42 e cada "token" ou elemento é rotulado com seu tipo, portanto, neste caso, seria Palavra-chave, Identificador, Operador, Número.
Abstract Syntax Tree (AST) : depois que o código é analisado em tokens, o analisador converte esses tokens em AST. Esta parte é chamada de "Parse" e faz o que diz, verifica erros de sintaxe no código.
Exemplo: Usando o exemplo de código acima, o AST para isso seria:
{
"type": "VariableDeclaration",
"start": 0,
"end": 13,
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 12,
"id": {
"type": "Identifier",
"start": 4,
"end": 7,
"name": "num"
},
"init": {
"type": "Literal",
"start": 10,
"end": 12,
"value": 42,
"raw":"42"
}
}
],
"tipo": "var"
}
Intérprete : Após a criação do AST, ele é passado para o interpretador, que processa o AST e gera o bytecode. Depois que o bytecode é gerado, ele é executado e o AST é removido.
Uma lista de bytecodes para V8 pode ser encontrada aqui .
Bytecode de exemplo para var num = 42; mostrado abaixo:
LdaConstant [0]
Star1
Mov <closure>, r2
CallRuntime [DeclareGlobals], r1-r2
LdaSmi [42]
StaGlobal [1], [0]
LdaUndefined
Return
Compilador : o compilador trabalha antecipadamente usando algo chamado "Profiler" que rastreia e segue o código que precisa ser otimizado. Se houver algo conhecido como "hot function", o compilador pega essa função e gera código de máquina otimizado para executar. Caso contrário, se ele perceber que uma "função quente" que foi otimizada não é mais usada, ele a "desotimizará" de volta para o bytecode.
Quando se trata do mecanismo JavaScript do Google V8, o pipeline de compilação é muito semelhante. Embora o V8 inclua um compilador "não otimizador" adicional que foi adicionado recentemente em 2021. Agora cada componente V8 tem um nome específico e são os seguintes:
Ignition : Um rápido interpretador V8 baseado em registro de baixo nível que gera bytecode.SparkPlug : um novo compilador JavaScript V8 não otimizador que compila a partir do bytecode iterando o bytecode e emitindo código de máquina para cada bytecode à medida que é visitado.
TurboFan : Um compilador de otimização V8 que converte bytecode em código de máquina com otimizações de código mais numerosas e complexas. Também inclui compilação JIT (Just-In-Time).
Juntando tudo, o pipeline de compilação V8 da visão geral se parece com isso:

https://forumupload.ru/uploads/001b/c9/09/2/t223372.png

Agora, não se preocupe se alguns desses conceitos ou recursos, como compiladores e otimizações, não fizerem sentido no momento. Não é necessário entender todo o pipeline de compilação para o post de hoje, mas devemos ter um entendimento básico de como o mecanismo funciona em geral. Daremos uma olhada mais de perto no pipeline V8 e seus componentes no segundo post desta série.
Até lá, se você quiser saber mais sobre o pipeline, sugiro dar uma olhada em " JavaScript Engines: The Good Parts " para entender melhor.
A única coisa que você deve entender deste pipeline de compilação neste momento é que o interpretador é uma " máquina de pilha ".” ou, na verdade, uma máquina virtual (VM) onde o bytecode é executado. Do ponto de vista do Ignition (o interpretador V8), o interpretador é na verdade uma "máquina registradora" com um registrador acumulador. O Ignition ainda usa a pilha, mas prefere armazenar dados em registradores para acelerar as coisas.
Sugiro que você leia " Entendendo o Bytecode V8 " e " Executando o Ignition Interpreter " para entender melhor esses conceitos.
JavaScript e internos V8

Agora que temos algum conhecimento básico de como funciona o mecanismo JavaScript e seu pipeline de compilação, é hora de nos aprofundarmos um pouco mais nas partes internas do JavaScript e ver como o V8 armazena e representa objetos JavaScript na memória, juntamente com seus valores e propriedades. .
Esta seção é uma das partes mais importantes que você precisa entender se quiser explorar erros no V8, bem como em outros mecanismos JavaScript. Porque, como se vê, todos os principais mecanismos implementam o modelo de objeto JavaScript de maneira semelhante.
Como sabemos, JavaScript é uma linguagem de tipagem dinâmica. Isso significa que as informações de tipo estão associadas a valores de tempo de execução em vez de variáveis ​​de tempo de compilação como em C++. Isso significa que as propriedades de qualquer objeto em JavaScript podem ser facilmente alteradas em tempo de execução. O JavaScript Type System define tipos de dados como Undefined, Null, Boolean, String, Symbol, Number e Object (incluindo arrays e funções).
Em palavras simples, o que isso significa? Bem, isso geralmente significa que um objeto ou primitivo como var em JavaScript pode alterar seu tipo de dados em tempo de execução, ao contrário do C++. Por exemplo, vamos definir uma nova variável chamada item em JavaScript e defini-la como 42.
var item = 42;

Usando typeof emvariável de item do operador, vemos que ela retorna seu tipo de dado, que será Number.
typeof item
'number'

Agora, o que acontece se tentarmos definir o item como uma string e, em seguida, verificar seu tipo de dados?
item = "Olá!";
typeof item
'string'
Veja isso, a variável item agora está definida para um tipo de dados String e não um Number. Isso é o que torna o JavaScript "dinâmico" por natureza. Ao contrário do C++, se tentarmos criar uma variável int ou integer e depois tentarmos defini-la como uma string, ela falhará - assim:
int item = 3;
item = "Olá!"; // erro: conversão inválida de 'const char*' para 'int'
// ^~~~~~~~

Embora isso seja legal em JavaScript, cria um problema para nós. V8 e Ignition são escritos em C++, portanto, o interpretador e o compilador precisam descobrir como o JavaScript usará alguns dados. Isso é muito importante para a compilação eficiente do código, principalmente porque em C++ existem diferenças nos tamanhos de memória para tipos de dados como int ou char.
Além da eficiência, isso também é crítico para a segurança, porque se o interpretador e o compilador "interpretarem" o código JavaScript incorretamente e acabarmos com um objeto de dicionário em vez de um objeto de matriz, teremos uma vulnerabilidade de confusão de tipos.
Então, como o V8 armazena todas essas informações para cada valor de tempo de execução e como o mecanismo permanece eficiente?
Bem, no V8 isso é obtido por meio do uso de um objeto de tipo de informação dedicado chamado Map (não confundir com Map Objects ), que também é conhecido como " Classe Oculta ". Ocasionalmente, você pode ouvir Map chamado " Shape ", especialmente no mecanismo JavaScript do Mozilla SpiderMonkey. O V8 também usa o que é chamado de compactação de ponteiro ou marcação de ponteiro na memória (que discutiremos mais adiante neste post) para reduzir o consumo de memória e permite que o V8 represente qualquer valor na memória como um ponteiro para um objeto.
Mas antes de nos aprofundarmos em como tudo funciona, primeiro precisamos entender o que são objetos JavaScript e como eles são representados na V8.
representação de objeto

Em JavaScript, os objetos são essencialmente um conjunto de propriedades que são armazenadas como pares chave-valor - significando essencialmente que os objetos se comportam como dicionários. Os objetos podem ser arrays, funções, booleanos, expressões regulares e assim por
diante.Todo objeto em JavaScript tem propriedades associadas a ele, que podem ser simplesmente explicadas como uma variável que ajuda a definir as características do objeto. Por exemplo, um objeto carro recém-criado pode ter propriedades como marca , modelo e ano que ajudam a determinar qual é o objeto carro. Você pode acessar as propriedades de um objeto com um operador de ponto simples como objectName.propertyName ou parênteses como objectName['propertyName'].
Além disso, cada propriedade de objeto é mapeada paraatributos de propriedade , que são usados ​​para definir e explicar o estado das propriedades do objeto. Um exemplo de como esses atributos de propriedade se parecem em um objeto JavaScript pode ser visto abaixo.

Agora que já entendemos um pouco o que é um objeto, o próximo passo é entender como esse objeto é estruturado na memória e onde ele é armazenado.

Sempre que um objeto é criado, o V8 cria um novo JSObject e aloca memória para ele no heap. O valor do objeto é um ponteiro para um JSObject que contém o seguinte em sua estrutura:
Mapa : Um ponteiro para um objeto HiddenClass que detalha a " forma " ou estrutura do objeto.
Propriedades : um ponteiro para um objeto que contém as propriedades nomeadas .
Elementos : um ponteiro para um objeto que contém as propriedades enumeradas .
Propriedade In-Object : Ponteiros para propriedades nomeadas que foram definidas quando o objeto foi inicializado.
Para ajudá-lo a visualizar isso, a imagem abaixo mostra como um V8 JSObject básico é estruturado na memória

https://forumupload.ru/uploads/001b/c9/09/2/t223372.png

Observando a estrutura JSObject, podemos ver que as propriedades e os elementos são armazenados em duas estruturas de dados FixedArray separadas , o que torna a adição e o acesso a propriedades ou elementos mais eficientes. A estrutura do elemento armazena predominantemente números inteiros não negativos ou propriedades indexadas por matriz (chaves), que são comumente chamadas de elementos. Quanto à estrutura da propriedade, se a chave da propriedade do objeto não for um número inteiro não negativo, como uma string, a propriedade será armazenada como uma propriedade do objeto integrado (explicado posteriormente no post) ou em a estrutura de propriedade, às vezes também chamada de armazenamento de suporte de propriedade do objeto.
Uma coisa que devemos observar é que, embora as propriedades nomeadas sejam armazenadas da mesma forma que os elementos da matriz, elas não são as mesmas quando se trata de acessar as propriedades. Ao contrário dos elementos, não podemos simplesmente usar uma chave para encontrar a posição das propriedades nomeadas na matriz de propriedades; precisamos de alguns metadados adicionais. Conforme mencionado anteriormente, o V8 usa um objeto especial chamado HiddenClass ou Map que está relacionado a JSObject. Todas as informações sobre objetos JavaScript são armazenadas lá, o que, por sua vez, permite que o V8 seja "dinâmico".
Portanto, antes de nos aprofundarmos no entendimento da estrutura de JSObject e suas propriedades, primeiro precisamos ver e entender como essa HiddenClass funciona na V8.

HiddenClass(Mapa) e Transições de Forma

Conforme discutido anteriormente, sabemos que JavaScript é uma linguagem de tipagem dinâmica. Principalmente por causa disso, não existe o conceito de classes em JavaScript. Em C++, se você criar uma classe ou objeto, não poderá adicionar ou remover métodos e propriedades imediatamente, ao contrário do JavaScript. Em C++ e outras linguagens orientadas a objetos, você pode armazenar as propriedades do objeto em um deslocamento fixo na memória porque o layout de um objeto para uma instância de uma determinada classe nunca mudará, mas em JavaScript ele pode mudar dinamicamente em tempo de execução. Para combater isso, o JavaScript usa o que é conhecido como " herança baseada em protótipo ", onde cada objeto tem uma referência a um objeto protótipo ou "forma" cujas propriedades ele inclui.

Então, como o V8 armazena o layout de um objeto?

É aqui que HiddenClass ou Map entra em ação. As classes ocultas funcionam de maneira semelhante ao layout de objeto fixo, onde os valores das propriedades (ou ponteiros para essas propriedades) podem ser armazenados em uma estrutura de memória específica e, em seguida, acessados ​​com um deslocamento fixo entre cada um. Esses deslocamentos são gerados pelo Torque e podem ser encontrados em /torque-generated/src/objects/*.tq.inc . Isso serve em grande parte como um identificador para a "forma" do objeto, o que, por sua vez, permite que o V8 otimize melhor o código JavaScript e reduza os tempos de acesso à propriedade.
Como visto anteriormente em JSObject, no exemplo acima, map é outra estrutura de dados dentro de um objeto. Esta estrutura contém as seguintes informações:
O tipo dinâmico do objeto, como String, JSArray, HeapNumber, etc.
Os tipos de objeto na V8 são listados em /src/objects/objects.h
Tamanho do objeto (propriedades intra-objeto, etc.)
Propriedades do objeto e onde elas são armazenadas
Tipo de elemento da matriz
Protótipo ou forma do objeto (se houver)
Para ajudar a visualizar a aparência do objeto de mapa na memória, forneci o mapa V8 na imagem abaixo. Mais informações sobre estruturas podem ser encontradas no código-fonte V8, bem como em /src/objects/map.h e /src/objects/descriptor-array.h .

https://forumupload.ru/uploads/001b/c9/09/2/t514738.png


Agora que entendemos como é o layout do mapa, vamos explicar essa "forma" da qual falamos o tempo todo. Como você sabe, cada JSObject recém-criado terá sua própria classe oculta que contém o deslocamento de memória para cada uma de suas propriedades. Aqui está a parte interessante; se a qualquer momento uma propriedade deste objeto for criada, excluída ou alterada dinamicamente, uma nova classe oculta será criada.Esta nova classe oculta armazena informações sobre as propriedades existentes, incluindo o deslocamento de memória para a nova propriedade. Agora observe que uma nova classe oculta só é criada quando uma nova propriedade é adicionada, adicionar uma propriedade com um índice de array não cria novas classes ocultas.
Então, como isso se parece na prática? Ok, vamos ver o seguinte código:

var obj1 = {};
obj1.x = 1;
obj1.y = 2;
Primeiro, criamos um novo objeto denominado obj1, que é criado e armazenado no heap V8. Como este é um objeto recém-criado, precisamos criar uma HiddenClass (obviamente) mesmo que nenhuma propriedade tenha sido definida para este objeto ainda. HiddenClass também é criado e armazenado no heap V8. Para fins de nosso exemplo, chamaremos essa HiddenClass de "C0".

https://forumupload.ru/uploads/001b/c9/09/2/t280064.png

Assim que a próxima linha de código for alcançada e obj1.x = 1 for executado, o V8 criará uma segunda HiddenClass chamada "C1" com base em C0. C1 será a primeira HiddenClass descrevendo o local da propriedade where. x pode ser encontrado na memória. Mas, em vez de armazenar um ponteiro para o valor de x, ele armazenará o deslocamento de x, que estará no deslocamento 0.

https://forumupload.ru/uploads/001b/c9/09/2/t822357.png

Ok, eu sei que neste ponto alguns de vocês podem estar se perguntando: "Por que a compensação é para uma propriedade e não seu valor"?

Bem, no V8 é um truque de otimização. Mapas são objetos relativamente caros em termos de uso de memória. Se armazenarmos pares de propriedade de valor-chave de formato de dicionário em cada JSObject recém-criado, isso causará muita sobrecarga computacional, pois a análise de dicionários é lenta. Em segundo lugar, o que acontece se um novo objeto, como obj2, for criado com as mesmas propriedades de obj1, como x e y? Mesmo que os valores possam ser diferentes, os dois objetos na verdade possuem as mesmas propriedades nomeadas na mesma ordem, ou como chamaríamos, na mesma " forma "". Nesse caso, seria um desperdício armazenar o mesmo nome de propriedade em dois lugares diferentes.
E isso permite que o V8 seja rápido, é otimizado de forma que o mapa seja o mais amplamente distribuído possível entre objetos da mesma forma. Como os nomes de propriedade são repetidos para todos os objetos no mesmo formulário e porque estão na mesma ordem, pode haver vários objetos apontando para uma única HiddenClass no deslocamento de memória para propriedades em vez de ponteiros para valores. Também simplifica a coleta de lixo, pois o mapa é sobre alocação de memória. Para explicar melhor esse conceito, vamos voltar um pouco ao nosso exemplo acima e examinar as partes importantes da HiddenClass. As duas partes mais importantes da HiddenClass que permitem que o Map tenha sua "forma" são o DescriptorArraye um campo de terceiro bit. Se você voltar à estrutura Map acima, notará que o campo do terceiro bit armazena o número de propriedades, e o array descritor contém informações sobre as propriedades nomeadas, como o próprio nome, a posição onde o valor é armazenado (deslocamento ). e atributos de propriedade.
Por exemplo, suponha que criamos um novo objeto como var obj {x: 1}. A propriedade x será armazenada nas propriedades In-Object ou no armazenamento de propriedades do objeto JavaScript. Como um novo objeto está sendo criado, uma nova HiddenClass também será criada. Dentro desta HiddenClass, um array de descritores e um campo de terceiro bit serão preenchidos. O campo do terceiro bit define numberOfOwnDescriptors como 1, pois temos apenas uma propriedade e, em seguida, a matriz do descritor preencherá as partes de chave, detalhe e valor da matriz com informações relacionadas à propriedade x. O valor deste descritor será 0. Por que 0? Bem, as propriedades In-Object e o armazenamento de propriedades são apenas uma matriz. Assim, definindo o valor do descritor como 0, o V8 sabe que o valor das chaves estará no offset 0 deste array para qualquer objeto de mesmo formato.

Um exemplo ilustrativo do que acabamos de explicar pode ser visto abaixo.
https://forumupload.ru/uploads/001b/c9/09/2/t345257.png

Vamos ver como fica no V8. Primeiro, execute d8c --allow-natives-syntax e execute o seguinte código JavaScript:
d8> var obj1 = {a: 1, b: 2, c: 3}

Depois de concluído, usaremos %DebugPrint() em nosso objeto para exibir suas propriedades, mapa e outras informações, como o identificador de instância. Após a conclusão, preste atenção a:

https://forumupload.ru/uploads/001b/c9/09/2/t223218.png

Vamos destacar nosso objeto obj1 em amarelo. Ponteiro vermelho para nosso HiddenClass ou Map. Nesta HiddenClass temos um descritor de instância que aponta para um DescriptorArray. Usando %DebugPrintPtr() , um ponteiro para este array, podemos ver mais detalhes sobre como este array se parece na memória, que está destacada em azul .
Observe que temos três propriedades, que correspondem ao número de descritores na seção de descritores das instâncias do mapa. Abaixo vemos que o array do descritor contém nossas chaves de propriedade, e o campo de dados const contém os deslocamentos de seus valores associados no armazenamento de propriedades. Agora, se seguirmos a seta de volta dos deslocamentos para nosso objeto, perceberemos que os deslocamentos realmente correspondem e cada propriedade recebe o valor correto.

Além disso, observe que à direita dessas propriedades, você pode ver a localização de cada uma delas; que estão no objeto como mencionei anteriormente. Isso praticamente prova para nós que os deslocamentos referem-se a propriedades no armazenamento In-Object e Properties.

Ok, agora que entendemos por que usamos compensações, vamos voltar ao nosso exemplo HiddenClass anterior. Como dissemos, adicionando a propriedade x a obj1, agora temos uma HiddenClass recém-criada chamada "C1" compensada por x. Como estamos criando uma nova HiddenClass, o V8 atualizará C0 com uma "transição de classe", que diz que, se um novo objeto for criado com a propriedade x, a classe oculta deverá alternar diretamente para C1.
O processo então se repete quando obj1.y = 2. Uma nova classe oculta chamada C2 será criada e uma transição de classe adicionada a C1 indicando que, para qualquer objeto com propriedade x, se a propriedade y for adicionada, a classe oculta deve fazer a transição para C2 . No final, todas essas transições de classe criam algo conhecido como "árvore de transição".

https://forumupload.ru/uploads/001b/c9/09/2/t447200.png

Além disso, observe que as transições de classe dependem da ordem em que as propriedades são adicionadas a um objeto. Assim, se z fosse adicionado depois de y, a "forma" não seria mais a mesma e seguiria o mesmo caminho de transição de C1 para C2. Em vez disso, uma nova classe oculta será criada e um novo caminho de navegação de C1 será adicionado para dar conta dessa nova propriedade, expandindo ainda mais a árvore de navegação.

Além disso, observe que as transições de classe dependem da ordem em que as propriedades são adicionadas a um objeto. Assim, se z fosse adicionado depois de y, a "forma" não seria mais a mesma e seguiria o mesmo caminho de transição de C1 para C2. Em vez disso, uma nova classe oculta será criada e um novo caminho de navegação de C1 será adicionado para dar conta dessa nova propriedade, expandindo ainda mais a árvore de navegação.
d8> var obj1 = {x: 1, y: 2};
d8> var obj2 = {x: 2, y: 3};
Depois de concluído, usaremos novamente %DebugPrint() em cada um de nossos objetos para exibir suas propriedades, mapa e outras informações. Depois de fazer isso, preste atenção ao seguinte:

0

2

Ster410вдалBettГорбБукаЦ-90ПравАндрГречСогрBistАМЗо(183PleaнаучГабр1с31БойкRotoскулГусе
StefопубTescZyliBoazTerrВышеSonyDaniлатиAlfrШебарабовозрBrilDuomKeraJuicDropKissAlexHora
PaleуволиллюNatiOmsaсертEspeKinsКитамолнНевеPeneпробзатротвеOZONШумаQuikSilvRIALPrinPrin
StuaJuliНаумFritКарнXVIIКаспминуWorkClifZoneавтосложMORGdiamСодеGlenКедр3210ZoneскрыNaso
хар-МалыZoneZoneСодеSofiаппаСемиматеНахтPierфакурабопортCharТуроСедоопубюридDaniГригGeor
ФормРыжоJameСлуж48-5РабопатиклейCDMAколлNardMielKronAnnaNaruMiniфигуDCHSРоссZENIGhosДюко
STARGenuMITSГермврачModeKarmрисокистYuicфишккомпTrudWindKaspTangWinxSwisRoweсертEukaДани
BambЛитРЛитРЛитРКругВоейВасиMarcЛитРРадхактиШмелперепремXVIIСанжстат1307допоInteLiyaSpin
GoodредаАлекБелоОконабитAlexМалеSpacNougНахиГорбдопоJeweкадрКрылБахчClasТопоНатаcasuавто
AlbaXVIIЛипоКозыобучобщевыруCDMACDMACDMAЛукиNighAstrSamsBlacавтознанКасьпоэтхудоБредавто
tuchkasGregкоти

0


Вы здесь » COVIL HACKER » Vulnerabilidades/exploração de software » Artigo Explorando o navegador Chrome, Parte 1: Introdução à V8 e ao Ja


Рейтинг форумов | Создать форум бесплатно