Няшная / Говнокод #27973 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
// тред лоулевел-хаков #1

#include <stdio.h>
#include <stdlib.h>

void hello(void)
{
        puts("Hello!");
}

void goodbye(void)
{
        puts("Goodbye!");
}

void set_sp_(void *p)
{
        void *s[0];
        s[0] = p;
}

void set_sp(void *p)
{
        set_sp_((void*)p);
}

int main(void)
{
        void *new_stack[1024] = {
                [1019] = (void*)0,
                [1020] = (void*)&hello,
                [1021] = (void*)&goodbye,
                [1022] = (void*)&exit
        };
        set_sp((void*)&new_stack[1019]);
        return 0;
}

UB-ы, платформенно зависимый кот, битовая магия

всё сюда
|
|
\/

Запостил: Hu3KoypoBHeBblunemyx Hu3KoypoBHeBblunemyx, (Updated )

Комментарии (35) RSS

  • Циклы реализованые через фрейм пойнтер и фикс адреса возврата, автор, предположительно, inkanus_gray:
    #include <stdio.h>
    typedef struct {
      int endValue;
      void * startBody;
    } loop_record;
    
    loop_record stack[1000];
    int head = 0;
    
    void push(loop_record value) {
        stack[head] = value;
        head++;
    }
    
    loop_record pop() {
        head--;
        if (head < 0) exit(255);
        return stack[head];
    }
    
    void _do(void * label, int * counter, int from, int to) {
      void ** frame = __builtin_frame_address(0);
      *counter = from;
    
      if (*counter > to) {
        frame[1] = label;  // Эквивалент goto *label
        return;
      }
    
      loop_record current;
      current.endValue = to;
      current.startBody = frame[1];
      push(current);
    }
    
    void _next(int * counter) {
      void ** frame = __builtin_frame_address(0);
      (*counter)++;
    
      loop_record current = pop();
      if (*counter <= current.endValue) {
        push(current);
        frame[1] = current.startBody; // Эквивалент goto *startBody (на след. инструкцию после вызова _do)
      }
    }
    
    int main() {
      int i;
      _do(&&end,&i, 1, 5);
        printf("Хорошо живёт на свете Винни-пух (%d).\n", i);
      _next(&i);
      end:
        printf("Оттого поёт он эти песни вслух.\n");
    }
    Ответить
    • #include <stdio.h>
      typedef struct {
        int endValue;
        void * startBody;
      } loop_record;
      
      loop_record stack[1000];
      int head = 0;
      
      void push(loop_record value) {
          stack[head] = value;
          head++;
      }
      
      loop_record pop() {
          head--;
          if (head < 0) exit(255);
          return stack[head];
      }
      
      void _for(int * counter, int from, int to) {
        void ** frame = __builtin_frame_address(0);
        *counter = from;
      
        loop_record current;
        current.endValue = to;
        current.startBody = frame[1];
        push(current);
      }
      
      void _next(int * counter) {
        void ** frame = __builtin_frame_address(0);
        (*counter)++;
      
        loop_record current = pop();
        if (*counter <= current.endValue) {
          push(current);
          frame[1] = current.startBody; // Эквивалент goto *startBody (на след. инструкцию после вызова _do)
        }
      }
      
      int main() {
        int i;
        _for(&i, 1, 5);
          printf("Хорошо живёт на свете Винни-пух (%d).\n", i);
        _next(&i);
        printf("Оттого поёт он эти песни вслух.\n");
      }
      Ответить
      • таблица переходов оттуда же
        #include <stdio.h>
        #include <setjmp.h>
        #include <string.h>
        typedef struct {
          jmp_buf environ;
        } loop_record;
        
        loop_record stack[1000];
        int head = 0;
        
        void push(loop_record value) {
            stack[head] = value;
            head++;
        }
        
        loop_record pop() {
            head--;
            if (head < 0) exit(255);
            return stack[head];
        }
        
        void _switch(int counter, void ** labels) {
          jmp_buf env;
          int jmpval = setjmp(env);
        
          if (jmpval == 0) {
            loop_record current;
            memmove(current.environ, env, sizeof(env));
            push(current);
            void ** frame = __builtin_frame_address(0);
            frame[1] = labels[counter];
          } else {
            void ** frame = __builtin_frame_address(0);
            frame[1] = labels[0]; // выходим
          }
        }
        
        void _break() {
          loop_record current = pop();
          longjmp(current.environ, 1);
        }
        
        int main() {
          void * jmpTable[] = {&&end, &&case_1, &&case_2, &&case_3};
          _switch(2, jmpTable);
            case_1:
            printf("Первый багор.\n");
            _break();
            case_2:
            printf("Второй багор.\n");
            _break();
            case_3:
            printf("Третий багор.\n");
            _break();
          end:
          printf("Всё!.\n");
        }
        Ответить
        • #include <stdio.h>
          typedef struct {
            void * ret;
          } loop_record;
          
          loop_record stack[1000];
          int head = 0;
          
          void push(loop_record value) {
              stack[head] = value;
              head++;
          }
          
          loop_record pop() {
              head--;
              if (head < 0) exit(255);
              return stack[head];
          }
          
          void _switch(int counter, void ** labels) {
              loop_record current;
              current.ret = labels[0];
              push(current);
              void ** frame = __builtin_frame_address(0);
              frame[1] = labels[counter];
          }
          
          void _break() {
              loop_record current = pop();
              void ** frame = __builtin_frame_address(0);
              frame[1] = current.ret;
          }
          
          int main() {
            void * jmpTable[] = {&&end, &&case_1, &&case_2, &&case_3};
            _switch(2, jmpTable);
              case_1:
              printf("Первый багор.\n");
              _break();
              case_2:
              printf("Второй багор.\n");
              _break();
              case_3:
              printf("Третий багор.\n");
              _break();
            end:
            printf("Всё!.\n");
          }
          Ответить
      • puts("Хорошо живёт на свете Лоулевельный Питух\n");
        puts("Оттого поёт он эти хаки вслух.\n");
        Ответить
  • Мне всё лень было разбиратся, а оказывается там на стеке просто питуз
    nemyx@pryschi:~$ cat test.c
    #include <stdio.h>
    #include <stdlib.h>
    
    void hello(void)
    {
            puts("Hello!");
    }
    
    void goodbye(void)
    {
            puts("Goodbye!");
    }
    
    void set_sp_(void *p)
    {
            void *s[0];
            s[1] = p;
    }
    
    void set_sp(void *p)
    {
            set_sp_((void*)p);
    }
    
    int main(void)
    {
            void *new_stack[1024] = {
                    [1019] = (void*)0,
                    [1020] = (void*)&hello,
                    [1021] = (void*)&goodbye,
                    [1022] = (void*)&exit
            };
            set_sp((void*)&new_stack[1019]);
            return 0;
    }
    
    nemyx@pryschi:~$ gcc -g -fstack-protector test.c
    nemyx@pryschi:~$ ./a.out
    Hello!
    Goodbye!
    nemyx@pryschi:~$
    Ответить
      • Ого питушня какая
        (gdb) disassemble set_sp_
        Dump of assembler code for function set_sp_:
           0x000000000000116b <+0>:     push   %rbp
           0x000000000000116c <+1>:     mov    %rsp,%rbp
           0x000000000000116f <+4>:     sub    $0x20,%rsp
           0x0000000000001173 <+8>:     mov    %rdi,-0x18(%rbp)
           0x0000000000001177 <+12>:    mov    %fs:0x28,%rax
           0x0000000000001180 <+21>:    mov    %rax,-0x8(%rbp)
           0x0000000000001184 <+25>:    xor    %eax,%eax
           0x0000000000001186 <+27>:    mov    -0x18(%rbp),%rax
           0x000000000000118a <+31>:    mov    %rax,-0x8(%rbp)
           0x000000000000118e <+35>:    nop
           0x000000000000118f <+36>:    mov    -0x8(%rbp),%rax
           0x0000000000001193 <+40>:    xor    %fs:0x28,%rax
           0x000000000000119c <+49>:    je     0x11a3 <set_sp_+56>
           0x000000000000119e <+51>:    callq  0x1040 <__stack_chk_fail@plt>
           0x00000000000011a3 <+56>:    leaveq
           0x00000000000011a4 <+57>:    retq
        End of assembler dump.
        Ответить
        • Хм, просто канарейку положили перед сохранёнными rbp/rip и называют это strong?

          Впрочем, от переполнения буфера это действительно спасёт т.к. задев сохранённый rbp или rip ты неизбежно заденешь и канарейку (т.к. она отделяет их от локалок).
          Ответить
          • Ага, а с твоим -fstack-protector на стеке просто какой-то лишний петух. Только от переполнения на 1 спасёт
            Dump of assembler code for function set_sp_:
               0x000000000000115b <+0>:     push   %rbp
               0x000000000000115c <+1>:     mov    %rsp,%rbp
               0x000000000000115f <+4>:     mov    %rdi,-0x8(%rbp)
               0x0000000000001163 <+8>:     mov    -0x8(%rbp),%rax
               0x0000000000001167 <+12>:    mov    %rax,0x0(%rbp)
               0x000000000000116b <+16>:    nop
               0x000000000000116c <+17>:    pop    %rbp
               0x000000000000116d <+18>:    retq
            End of assembler dump.
            Ответить
            • > какой-то лишний петух

              Я здесь вообще не вижу никаких стек протекторов, просто кто-то забыл включить оптимизацию и конпелятор был вынужден сохранять аргумент на стек чтобы отладчику потом не пришлось выковыривать его из других фреймов.
              Ответить
              • Ой, я не то запостил)
                Dump of assembler code for function set_sp_:
                   0x000000000000115b <+0>:     push   %rbp
                   0x000000000000115c <+1>:     mov    %rsp,%rbp
                   0x000000000000115f <+4>:     mov    %rdi,-0x18(%rbp)
                   0x0000000000001163 <+8>:     mov    -0x18(%rbp),%rax
                   0x0000000000001167 <+12>:    mov    %rax,0x0(%rbp)
                   0x000000000000116b <+16>:    nop
                   0x000000000000116c <+17>:    pop    %rbp
                   0x000000000000116d <+18>:    retq
                End of assembler dump.
                Ответить
                • Мне нужно найти 10 отличий?

                  Возможно, конпелятор охуел от обращения к массиву из 0 элементов, подумал что это в любом случае UB и не стал вставлять протектор.

                  З.Ы. А, вижу, там просто зазор от локалок до границы фрейма больше стал. Кстати прикольно, на этом примере видно, как конпелятор юзает редзону не двигая rsp. В ядре такой код пизданулся бы на первом прерывании.
                  Ответить
                  • Да, зазорчик между концом мосива и фрейм пойнтером.

                    А я сперва подумал, что там блу канари)

                    > В ядре такой код пизданулся бы
                    А для едра с каким ключиком конпелять?
                    Ответить
                  • Потому что обработчик прерывания в душе не ебет что ты там в крсную зону насрал?
                    Ответить
                    • Ну да. Хотя в теории можно было бы немного переделать проц, чтобы он мог немного отступать на входе в прерывание. Пирфоманс ядрёного кода был бы выше...
                      Ответить
                • А, понятно.

                  This includes functions that call alloca, and functions with buffers larger than or equal to 8 bytes. У тебя буфер маловат, гцц считает, что его невыгодно/нинужно защищать.

                  А strong уже на все функции с массивами работает.
                  Ответить
                        • В «ПХП» вообще нельзя сравнивать типы. Можно сравнивать значения.

                          Поэтому нужно либо создавать экземпляры классов, либо сравнивать их статические свойства. Например, есть встроенное свойство class, которое возвращает его имя:

                          A::class == B::class

                          Вернёт false, потому что 'A' не равно 'B'.
                          Ответить
        • З.Ы. И ты как раз в канарейку и хуйнул свой указатель судя по строке 0x118a. Попробуй s[2] = p.
          Ответить
            • Подправил версию для ideone: https://ideone.com/m4xsxq
              Походу они с оптимизациями собирают
              (gdb) disassemble set_sp_
              Dump of assembler code for function set_sp_:
                 0x000000000000115f <+0>:     retq
              End of assembler dump.
              (gdb) Quit
              (gdb) disassemble set_sp
              Dump of assembler code for function set_sp:
                 0x0000000000001160 <+0>:     retq
              End of assembler dump.
              Какой багор )))
              Ответить
            • > xor %eax, %eax

              Чтобы предотвратить утечку печеньки, видимо.

              > nop

              Не помню, если честно. Он то ли для раскрутки стека нужен то ли для отладчика, чтобы однозначно понимать, в теле функции мы навернулись или в эпилоге (иначе не отличить трапа в инструкции n от фолта в инструкции n + 1). Заметь, что стоит он между джвумя инструкциями, которые лезут к памяти.
              Ответить

Добавить комментарий

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8