Jump to content

Lucas Rodrigues

Apoiador Nibble
  • Posts

    5
  • Joined

  • Last visited

Posts posted by Lucas Rodrigues

  1. Tem uma outra forma de fazer essa conversão que acho sensacional, que simplesmente usa bitwise e codifica em HEX baseado no ASCII. Essa forma é mais segura contra cache timing attack, inclusive versões similares são usados pela BoringSSL para decodificar os certificados e tal, o negativo é a performance, que é bizarramente mais lenta.

    Eu não sou nada bom em C, mas fiz um esforço para sair alguma coisa razoável, se tiver sugestão de melhorias eu agradeço.

    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    #define SIZE 255
    
    struct hexResult {
        uint64_t i;
        uint64_t e;
    };
    
    struct hexResult hexToDec(char str[]) {
        struct hexResult r = {0, 0};
    
        for (int i = 0; i < _mbstrlen(str); i++) {
            uint64_t b = str[i] - (uint64_t) 48;
            b -= (((uint64_t) 9 - b) >> (uint64_t) 8) & (uint64_t) 7;
            b -= (((uint64_t) 41 - b) >> (uint64_t) 8) & (uint64_t) 32;
    
    
            r.e |= ((b >> (uint64_t) 8) | ((uint64_t) 15 - b) >> (uint64_t) 8) & (uint64_t) 1;
            r.i |= b << (uint64_t) (4 * i);
        }
    
        return r;
    }
    
    int main(void) {
        int opcao;
        char str[SIZE];
    
        printf("Insira o hexadecimal: ");
        scanf("%s", str);
    
        struct hexResult result = hexToDec(str);
        if (result.e) {
            printf("%s", "Caracteres invalidos foram detectados");
        }
    
        printf("%lld", result.i);
    
        return 0;
    }

     

    Isso é só para decodificar o hexadecimal para uint64. Acredito que o resto possa ser feito da mesma forma. A ideia é bem simples, basicamente. 

    Assumimos que "A" é 10, assim como "1" é 1. O "A" no ASCII é o 65 (em inteiro), portanto se fizermos 65-55 teremos exatamente o 10, assim como "1" que em ASCII é o 49, podemos fazer simplesmente 49-48 que daria 1, exatamente o mesmo valor que o "1" vale em hexadecimal.

     

    Para evitar usar o if, para mitigar timing-attack (e similares) o que se faz é compara se o número é menor ou maior  usando bitwise. Neste trecho especifico:

    b = str[i] - (uint64_t) 48;

    Todos os caracteres serão subtraídos por 48. Dessa forma o "1" será 1, assim com o "9" será 9. Porém, o "A" será 17, porque existe uma lacuna no ASCII entre o números e letras, por isso existe a segunda linha:

    b -= (((uint64_t) 9 - b) >> (uint64_t) 8) & (uint64_t) 7;

     

    Então, se o número for maior que 9 ele será um número negativo. Veja que 9-10 = -1, mas 9 - 9 = 0 e 9-8 = 1. Então o que queremos é saber se ele é ou não maior do que 9. Para isso fazemos o shift para pegar o resto dos bits, após os 7 primeiros bits, já que o numero nunca irá exceder 7 bits. Se ele for negativo  o bit do sinal de 1 será propagado pelo shift, ficando 11111111.... O and entre o -1 & 7 irá funcionar, assim ficará b -= 7. Porém, se for positivo, todos os bits a esquerda serão 0, então o shift também sera tudo 0, e consequentemente o and não irá funcionar, assim ficará b -= 0 & 7 que será b -= 0;

     

    A mesma lógica se aplica aos demais casos. Isso é apenas uma outra forma de resolver, sem usar if e nem tabelas. Eu não sei há outros erros, lembre-se que não estou acostumado com o C, e não uso ele. :)

    • l33t 2
  2. Existem alguma forma de sugerir edições ou de criar novos conteúdos para o livro (https://mentebinaria.gitbook.io)?

     

    Por exemplo, na parte de numerações, acredito que faltam informações sobre o ordenamento de bytes (BigEndian/LittleEndian) que podiam ser acrescentadas em "O Bytes" (https://mentebinaria.gitbook.io/engenharia-reversa/numeros/o-byte), talvez. Esta informação poderia ser também mencionada em https://mentebinaria.gitbook.io/engenharia-reversa/textos/unicode#utf-16, que menciona o endianess, com um link para o assunto.

     

    No mesmo ponto, no UNICODE também poderia informar como é feito para sinalizar a existência de um outro byte, no caso do UTf-8 especificamente. Apenas para mencionar o que quero dizer, o UTF-8 será um ASCII quando usado um único byte (0xxxxxxx), porém quando tem dois ele obrigatoriamente será (110xxxxx) e todos os bytes  seguintes, que não o primeiro, devem ser (10xxxxxx). Acho que isto pode ser uma informação relevante, inclusive por isso ele não tem o problema de BigEndian/LittleEndian, que ocorre com o UTF-16... 

    > PS: Eu não li tudo ainda, pode ser que essas informações existem em algum outro ponto.

  3. Isso é extremamente útil para funções como o mysqli_stmt_bind_param, nativo do PHP.

    $array = ['Um', 'Dois', 'Tres', 4];
    
    $stmt = mysqli_prepare($link, "INSERT INTO Tabela VALUES (?, ?, ?, ?)");
    mysqli_stmt_bind_param($stmt, 'sssd', ...$array);
    
    mysqli_stmt_execute($stmt);

     

    Assim você pode usar um array direto no mysqli_stms_bind_param, devido ao uso do ...$array. ;)

    • Agradecer 1
×
×
  • Create New...