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

0

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

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

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

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

Комментарии (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;
        Ответить
          • $IFNDEF DPMI же, для реалмода. В защищённом такая питушня не пройдёт.

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

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

Переведи на "PHP", guest!

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


    8