1. Си / Говнокод #20289

    −47

    1. 1
    http://ache.vniz.net/demos.html

    > Cвоеобразный программисткий подвиг совершил Дима Бурков. В то время начали появляться первые PC. Unix на них выглядел неубедительно. Linux еще не появился, зато повился Venix. Хачить его было невозможно - не было исходных текстов ядра. Дима Бурков реассемблировал ядро, потом писал программы на Си, которые давали тот же текст ассемблера - так появились тексты ядра на Си ... работа не для слабонервных.

    А вот интересно, можно ли сделать декомпилятор таким способом? Например, если известна точная версия GCC и флаги компиляции, которые использовались (ну и естественно исходники компилятора должны быть в наличии) то перебирать с эвристиками некий Си-код, пользуясь дизасм-листингом для подсказки и сравнения. Какой подход использует Hex-Rays например? Вряд ли они исходники GCC ковыряли

    Запостил: j123123, 28 Июня 2016

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

    • Ну, получишь ты царский код на си. Где всё заинлайнено, заанроллено, ни одна константа не именована, а все математические операции заменены на эквивалентную битовую магию. Что дальше делать будешь?
      Ответить
      • рефакторить, ггг)
        Ответить
      • Я бы использовал цепочку «компилятор — декомпилятор» в качестве оптимизатора: на входе анскилльный код, написанный заедушными питухами, на выходе — царский оптимальный код (особенно, когда куча ключей вроде -O3). Декомпилированный код можно потом выдавать за свой, чтобы все думали, что ты Царь или Роджер Хуй.
        Ответить
    • "в своё время мне хватило debug.com чтобы изучить ассемблер под x86" (c) Крис Касперски

      Кстати, я тоже так могу сделать, как Дима. С помощью inline assembly
      Ответить
    • Собсна, IDA с плагином Hex-Rays примерно так и делает. Правда, получается именно так, как сказал Antervis - Царский код.
      Ответить
    • > Вряд ли они исходники GCC ковыряли

      Вряд ли. IDA умеет распознавать (правда, на уровне подсказок в комментариях, а не полного декомпилятора) фрагменты кода, сгенерированного компиляторами с закрытым кодом, например, Турбо Паскаль, Delphi, Borland C, MSVC, Zortech C, вроде ещё какие-то позабытые компиляторы поддерживались.

      Как можно получить декомпилятор? Написать тестовые примеры для всех конструкций языка, которые декомпилятор собирается распознать, скомпилировать со всевозможными параметрами оптимизации и собрать листинги.

      Пример:
      #include <stdio.h>
      int main() {
        __asm("int 3"); 
        for(int i = 42; i < 265; i++) {
          __asm("int 3");
          printf("%d\n", i); // используем переменную i, чтобы её не выкинул оптимизатор
          __asm("int 3"); 
        }
        __asm("int 3");
      }


      Выхлоп gcc 5.3 для x86 без оптимизации:
      .LC0:
              .string "%d\n"
      main:
              pushq   %rbp
              movq    %rsp, %rbp
              subq    $16, %rsp
              int 3
              movl    $42, -4(%rbp)
      .L3:
              cmpl    $264, -4(%rbp)
              jg      .L2
              int 3
              movl    -4(%rbp), %eax
              movl    %eax, %esi
              movl    $.LC0, %edi
              movl    $0, %eax
              call    printf
              int 3
              addl    $1, -4(%rbp)
              jmp     .L3
      .L2:
              int 3
              movl    $0, %eax
              leave
              ret


      Мы видим, что for(int i = 42; i < 265; i++) { соответствует фрагмент:
      movl    $42, -4(%rbp)
      .L3:        cmpl    $264, -4(%rbp)
              jg      .L2

      А завершению цикла соответствует
      addl    $1, -4(%rbp)
              jmp     .L3
      .L2:

      Увидев в листинге дизассемблера похожие фрагменты, декомпилятор может сгенерировать цикл for.
      Ответить
      • Ну вот, а говорят что фарш невозможно провернуть назад
        Ответить
        • Если код изначально царский, а не лаба, то мясо из котлет не восстановишь.
          Ответить
        • А вообще я подобным способом в своё время восстановил GRAPH.PAS из GRAPH.TPU от седьмого Турбо Паскаля. Восстановленный исходник компилировался неродным компилятором и даже работал.

          Правда, внутри было примерно шесть килобайт отборного царского кода, который мне пришлось так и оставить в двоичном виде, не декомпилируя.

          Вот фрагмент того фарша, который удалось провернуть назад:
          Function Graph_Num2Str(x:longint):string; near;
           var s:string[6];
           begin
            Str(x:0,s);
            Graph_Num2Str:=s
           end;
          Const
           aBgiErrorGraphicsNotInitialized=
            'BGI Error: Graphics not initialized (use InitGraph)';
           aBgiErrorNotInGraphicsMode=
            'BGI Error:  Not in graphics mode';
          
          procedure __GraphNotInstalled; far;
           begin
            If Graph_Ingraphics=0 then
             WriteLn(Output, aBgiErrorGraphicsNotInitialized:0)
            else
             Writeln(Output, aBgiErrorNotInGraphicsMode:0);
            Halt(1)
           end;
          procedure Graph_DefaultGetMem(var P:pointer; Size:word); far;
          {$IFDEF DPMI}
          var
            Selector: Word;
          begin
            Selector := 0;
            if Size <> 0 then
                if MemAllocateBlock(0, Size, 2, nil, Selector) <> 0 then
                  Selector := 0;
            P := Ptr(Selector, 0);
          end;
          {$ELSE}
           var
            T: pointer;
           begin
            Size := (Size + 7) and $FFF8;
            GetMem(P, Size + 8);
            if P <> nil then
             begin
              if PtrRec(P).Ofs = 0 then
               begin
                 PtrRec(T).Ofs := Size and 15;
                 PtrRec(T).Seg := PtrRec(P).Seg + Size shr 4;
               end
              else
               begin
                T := P;
                PtrRec(P).Ofs := 0;
                Inc(PtrRec(P).Seg);
               end;
              FreeMem(T, 8);
             end
           end;
          {$ENDIF}
          {$IFDEF DPMI}
          function MemFreeBlock(Selector: Word): Integer; far;
          external 'RTM' index $0006;
          {$ENDIF}
          
          Procedure Graph_DefaultFreeMem(var arg_2:pointer;arg_0:word); far;
           begin
            If arg_2<>nil then
          {$IFNDEF DPMI}
             FreeMem(arg_2,arg_0);
          {$ELSE}
             MemFreeBlock(PtrRec(arg_2).Seg);
          {$ENDIF}
            arg_2:=nil
           end;
          Ответить
          • >> PtrRec(T).Seg := PtrRec(P).Seg + Size shr 4;
            ахуеть код
            Ответить
            • $IFNDEF DPMI же, для реалмода. В защищённом такая питушня не пройдёт.

              Но вообще тут просто праздник какой-то: выделяем на 8..16 байт больше, чем требуется, выравниваем, а потом лишний кусок освобождаем. Да, освобождаем кусок памяти по указателю, для которого явно не делали GetMem. Функции GetMem и FreeMem делала та же корпорация, что и модуль Graph, для них очевидно, ко-ко-ко-ко-как эти функции работают.
              Ответить
        • фарш то может быть и можно, а говно вряд ли
          Ответить

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