Декомпиляторы, или Что делать, если нужно восстановить исходники из бинарников?

Проблема восстановления исходного кода из скомпилированных бинарников возникает сравнительно часто и протекает остро, с воем и рыданиями. Здесь нам, до некоторой степени, помогут замечательные программы-декомпиляторы, и в этом посте автор собрал свои скромные попытки выдрать исходники (или хотя бы намёки на них) из скомпилированных из С-шного кода бинарников.


Задача для декомпилятора бинарников, собранных из С кода:
Классический случай: один деятель на факультете написал на правильном ANSI C (и используя библиотеки BLAS и LAPACK) нужные и хорошие алгоритмы, и скомпилировал их в виде MEX-файлов для использования (это С-шный код, который можно вызывать из МАТЛАБ).

Но потом он повздорил с народом, разозлился и свалил в частную контору, унеся все исходники с собой. Документации нет. Копий исходников нет. Есть обрывки личной переписки и намёки в сопровождающих файлах на тип алгоритма. Вариант физического воздействия на автора тупыми тяжёлыми предметами не рассматривается.

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


Кратко: суть и сложность проблемы
Декомпилятор (Decompiler) пытается перевести скомпилированный бинарный файл обратно в некое подобие исходного кода. Качество выхлопа зависит от особенностей языка исходника:
  • Для C# или Java есть много декомпиляторов - байткод на java содержит  много информации. Это помогает восстанавливать декомпилятору исходник до состояния, пригодного к повторной компиляции.
  • Совершенно другая история с двоичными файлами, в которых, как правило, отладочной информации нет. Тем не менее, динамически связанные библиотеки функций, как правило, вызываются по имени. Часто, типы параметров библиотечных функций известны, и это может помочь до известных пределов. 
Декомпиляторы пытаются восстановить информацию, которая частично утрачена при компиляции в бинарный файл - в этом и заключается основная сложность.

Если вы думаете, что с помощью декомпилятора вы получите обратно красивый код на С - вы будете сильно разочарованы.  В лучшем случае на выходе будет общая (и довольно грубая) структура программы, в худшем - только имена функций и немного мусора.

Так что ответ на вопрос заголовка поста: "Обхватить голову руками и закричать #$@@@@@!" :-)


Программы для декомпилирования (decompilers) для C/C++
Декомпиляторов для C/C++ немного, и ниже список из наиболее работоспособных. Здесь нет разделения на опенсорс или Linux-only - для такого дела, как вскрытие исходников, можно (и нужно) поступиться своими светлыми идеалами и наступить на горло собственной песне.

Сразу замечу: скорее всего, ни один декомпилятор не выдаст вам сразу компилируемый код. Придётся потратить порядком времени и сил, чтобы это месиво превратить в код, который можно читать (желательно, не только компилятору).


Boomerang
Boomerang это C decompiler с открытыми исходами:
  • поддерживаемые бинарные форматы:  ELF  PE-COFF Mac-OS
  • платформы: Windows/Linux
  • поддерживаемые архитектуры: IA32 MIPS PPC
  • метод работы: поточный, есть жалкий графический интерфейс, лучше использовать CLI.
Весьма продвинутый набор алгоритмов анализа кода, что не удивительно - один из соавтором защитил на этом докторскую диссертацию [Michael James Van Emmerik, Static Single Assignment for Decompilation, Ph.D. thesis, the University of Queensland, Australia. PDF, mirror PDF].

Качество кода, выдаваемого декомпилятором:
  • Структурирование: очень хорошее
  • Переменные: хорошее
  • Типы данных: очень хорошее
Выдаваемое качество кода сильно варьируется: некоторые функции почти идеально восстановлены, хорошо видна структура кода и есть указание типа переменных. В других случаях функции сильно запутаны и их почти невозможно прочитать.

Программа всё ещё в состоянии бета-версии и для больших проектов не подходит. Скачать можно здесь.


RecStudio
Интерактивный декомпилятор RecStudio для С и (отчасти) С++, закрытая разработка:
  • поддерживаемые бинарные форматыELF  PE-COFF AOUT RAW PS-X
  • платформы: Windows/Linux/MacOS
  • поддерживаемые архитектуры: x86 (ia32) x86_64 Mips PowerPC mc68k
  • метод работы: поточный и интерактивный, есть графический интерфейс.
Использует продвинутый набор алгоритмов анализа (partial Single Static Assignment, SSA), хотя до сих пор (и это после 20 лет!) в стадии разработки. Качество кода, выдаваемого декомпилятором:
  • Структурирование: хорошее
  • Переменные: частично
  • Типы данных: частично или никак
Выдаваемое качетсво кода, как правило, хуже, чем у Boomerang, хотя обновлённый RecStudio более подробен.

Программа работает вполне стабильно, есть сборки под Linux. Скачать можно здесь.



dcc - DOS to C decompiler
Поточный декомпилятор Dcc, только ANSI C  и для exe-файлов, с открытым исходным кодом под GPL:
  • поддерживаемые бинарные форматыEXE/COM
  • платформы: Windows
  • поддерживаемые архитектуры: x86
  • метод работы: поточный.
Один из первых декомпиляторов вообще, и только под DOS. Сильная сторона - структурирование кода. Качество кода, выдаваемого декомпилятором:
  • Структурирование: хорошее
  • Переменные: частично
  • Типы данных: частично или никак
Разработка Cristina Cifuentes, которая защитила PhD в Queensland University of Technology  на этом деле [можно полистать, если что - C. Cifuentes, Reverse Compilation Techniques].

Скачать можно отсюда (на сайте университета).



Hex Rays - plugin для IDA Pro
На самом деле Hex Rays не является отдельной программой - это плагин-декомпилятор для IDA Pro. Комбинация продвинутых возможностей IDA Pro (это дизассемблер) и Hex Rays в качестве декомпилятора очень впечатляет, как и аэрокосмическая цена.
По причине закрытости продукта (нет даже демо-версии) и нереальной цены в этом разделе про Hex Rays больше ничего написано не будет.




Ходовые испытания в реальных условиях
Для начала попробуем декомпилировать что-нибудь совсем простенькое и написанное на ANSI C и с использованем библиотеки BLAS для векторых и матричных операций. Бинарный файл можно скачать здесь.



1. Простенький C-шный бинарник + BLAS
Собственно, код на C для перемножения матрицы и вектора (используется CBLAS). Исходник:


#include <stdio.h>
#include <cblas.h>

double m[] = {
  3, 1, 3,
  1, 5, 9,
  2, 6, 5
};

double x[] = {
  -1, -1, 1
};

double y[] = {
  0, 0, 0
};

int main(void)
{
  int i, j;

  for (i=0; i<3; ++i) {
    for (j=0; j<3; ++j) printf("%5.1f", m[i*3+j]);
    putchar('\n');
  }

  cblas_dgemv(CblasRowMajor, CblasNoTrans, 3, 3, 1.0, m, 3, x, 1, 0.0, y, 1);


  for (i=0; i<3; ++i)  printf("%5.1f\n", y[i]);

  return 0;
}

После перемножения выдаст результат на консоль.

Выхлоп Boomerang
У него много ключей и параметров, часть которых не знает даже официальная, скажем так, документация. Тем не менее, для ключа -Td (Use data-flow-based type analysis) мы имеем выхлоп в стиле дзен:

double y;
double m = 3.;

// address: 0x80484e4
int main(int argc, char **argv, char **envp) {
    void *local23;   // r28

    for(;;) {
        proc1();
    }
}

Скажем так, не слишком ободряюще. Ключ  -Tc (Use old constraint-based type analysis) выдаёт больше информации к размышлению:

char y[24];
long long m[9] = { 0x4008000000000000LL, 0x3ff0000000000000LL, 0x4008000000000000LL, 0x3ff0000000000000LL, 0x4014000000000000LL, 0x4022000000000000LL, 0x4000000000000000LL, 0x4018000000000000LL, 0x4014000000000000LL };

// address: 0x80484e4
int main(int argc, char **argv, char **envp) {
    int local10;   // r24
    int local13;   // r28
    int local14;   // r29
    int local15;   // r32
    int local2;   // m[r28 + 72]{60}
    int local3;   // r28{181}
    int local6;   // m[r28 + 72]{119}
    int local7;   // m[r28 + 72]{149}
    int local8;   // m[r28 + 76]{9}
    int local9;   // m[r28 + 76]{49}

    *(int*)(local13 - 4) = local14;
    *(int*)(local13 - 12) = 0;
    local3 = local13 - 84;
    if (*(int*)(local3 + 72) > 2) {
        *(int*)(local3 + 52) = 1;
        *(int*)(local3 + 48) = 0x8049868;
        *(long long*)(local3 + 40) = 0.;
        *(int*)(local3 + 36) = 1;
        *(int*)(local3 + 32) = 0x8049848;
        *(int*)(local3 + 28) = 3;
        *(int*)(local3 + 24) = 0x8049800;
        *(long long*)(local3 + 16) = 1.;
        *(int*)(local3 + 12) = 3;
        *(int*)(local3 + 8) = 3;
        *(int*)(local3 + 4) = 111;
        *(int*)local3 = 101;
        cblas_dgemv();
        local6 = 0;
        for(;;) {
            *(long long*)(local3 + 4) = y[0];
            *(int*)local3 = 0x80486b6;
            proc1();
            local7 = *(int*)(local3 + 72) + 1;
        }
    }
    local8 = 0;
    for(;;) {
        local10 = *(int*)(local3 + 72) + *(int*)(local3 + 72) + *(int*)(local3 + 72);
        local15 = m[local10];
        *(long long*)(local3 + 4) = local15;
        *(int*)local3 = 0x80486b0;
        proc1();
        local9 = *(int*)(local3 + 76) + 1;
    }
} 
 

Подробностей тут больше, и тут выловлен самый главный ключик - cblas_dgemv();    


Выхлоп RecStudio
Намного более обилен и представляет собой следующий поток сознания:


// Generated by Rec Studio 4 - build Oct 20 2012

_init()
{// addr = 0x08048398
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t2;                         // _t2

    __esp = __esp - 4;
    L1();
    _pop(__ebx);
    if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
        __gmon_start__();
    }
    frame_dummy();
    __do_global_ctors_aux();
    _pop(__eax);
    return;
}

L080483A4()
{
    _unknown_ _t2;                         // _t2

    _pop(__ebx);
    if( *((intOrPtr*)(_t2 + 0x1414)) != 0) {
        __gmon_start__();
    }
    frame_dummy();
    __do_global_ctors_aux();
    _pop(__eax);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

__gmon_start__()
{// addr = 0x080483D8
    goto __imp____gmon_start__;
}

putchar()
{// addr = 0x080483E8
    goto __imp__putchar;
}

__libc_start_main()
{// addr = 0x080483F8
    goto __imp____libc_start_main;
}

cblas_dgemv()
{// addr = 0x08048408
    goto __imp__cblas_dgemv;
}

printf()
{// addr = 0x08048418
    goto __imp__printf;
}

_start(
    signed int __eax,                      // r0
    _unknown_ __edx                        // r3
)
{// addr = 0x08048430
    _unknown_ __ebx;                       // r1
    signed int _t5;                        // _t5
    _unknown_ _t6;                         // _t6
    _unknown_ _t10;                        // _t10

    __edx = __edx;
    _t4 = __eax;
    _pop(__esi);
    __ecx = __esp;
    __esp = __esp & 240;
    _push(__eax);
    _push(__esp);
    _push(__edx);
    _push(__libc_csu_fini);
    _push(__libc_csu_init);
    _push(__ecx);
    _push(_t10);
    _push(main);
    __libc_start_main();
    asm("hlt ");
    0;
    0;
    _push(0);
    _push(_t6);
    __esp = __esp - 4;
    if(completed.5982 != 0) {
    } else {
        _t4 = dtor_idx.5984;
        _t6 = ( &__DTOR_END__ -  &__DTOR_LIST__ >> 2) - 1;
        if(_t4 >= _t6) {
        } else {
            do {
                _t5 = _t4 + 1;
                dtor_idx.5984 = _t5;
                 *((intOrPtr*)(_t5 * 4 +  &__DTOR_LIST__))();
                _t4 = dtor_idx.5984;
            } while(_t4 < _t6);
        }
        completed.5982 = 1;
    }
    __esp = __esp + 4;
    _pop(__ebx);
    _pop(__ebp);
    return;
}

__do_global_dtors_aux(
    _unknown_ __esi                        // r5
)
{// addr = 0x08048460
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t4;                         // _t4
    signed int _t5;                        // _t5
    signed int _t6;                        // _t6
    _unknown_ _t10;                        // _t10

    if(completed.5982 == 0) {
        _t5 = dtor_idx.5984;
        _t10 = ( &__DTOR_END__ -  &__DTOR_LIST__ >> 2) - 1;
        if(_t5 >= _t10) {
L4:
            completed.5982 = 1;
            return;
        }
        do {
            _t6 = _t5 + 1;
            dtor_idx.5984 = _t6;
             *((intOrPtr*)(_t6 * 4 +  &__DTOR_LIST__))();
            _t5 = dtor_idx.5984;
        } while(_t5 < _t10);
        goto L4;
    }
    return;
}

frame_dummy()
{// addr = 0x080484C0
    _unknown_ __ebp;                       // r6

    __eax = __JCR_LIST__;
    if(__JCR_LIST__ == 0) {
    } else {
        __eax = 0;
        if(__eax != 0) {
             *__esp =  &__JCR_LIST__;
             *__eax();
            return;
        }
    }
    return;
}

main(
    _unknown_ __fp0                        // r28
)
{// addr = 0x080484E4
    signed int _v8;                        // _cfa_fffffff8
    signed int _v12;                       // _cfa_fffffff4
    intOrPtr _v32;                         // _cfa_ffffffe0
    char* _v36;                            // _cfa_ffffffdc
    intOrPtr _v48;                         // _cfa_ffffffd0
    char* _v52;                            // _cfa_ffffffcc
    intOrPtr _v56;                         // _cfa_ffffffc8
    char* _v60;                            // _cfa_ffffffc4
    intOrPtr _v72;                         // _cfa_ffffffb8
    intOrPtr _v76;                         // _cfa_ffffffb4
    intOrPtr _v80;                         // _cfa_ffffffb0
    _unknown_ __ebp;                       // r6

    __fp0 = __fp0;
    __esp = __esp & 240;
    __esp = __esp - 80;
    _v12 = 0;
    while(_v12 <= 2) {
        _v8 = 0;
        while(_v8 <= 2) {
            __fp0 ?_?  *((long long*)((_v12 + __edx + __edx + _v8) * 8 +  &m));
            asm("fstp qword [esp+0x4]");
             *__esp = 134514352;
            printf();
            _v8 = _v8 + 1;
        }
         *__esp = 10;
        putchar();
        _v12 = _v12 + 1;
    }
    _v32 = 1;
    _v36 =  &y;
    asm("fldz ");
    asm("fstp qword [esp+0x28]");
    _v48 = 1;
    _v52 =  &x;
    _v56 = 3;
    _v60 =  &m;
    asm("fld1 ");
    asm("fstp qword [esp+0x10]");
    _v72 = 3;
    _v76 = 3;
    _v80 = 111;
     *__esp = 101;
    cblas_dgemv();
    _v12 = 0;
    while(_v12 <= 2) {
        __fp0 ?_?  *((long long*)(_v12 * 8 +  &y));
        asm("fstp qword [esp+0x4]");
         *__esp = "%5.1f\n";
        printf();
        _v12 = _v12 + 1;
    }
    return 0;
}

__libc_csu_fini()
{// addr = 0x080485F0
    _unknown_ __ebp;                       // r6

    return;
}

__libc_csu_init(
    intOrPtr _a4,                          // _cfa_4
    intOrPtr _a8,                          // _cfa_8
    intOrPtr _a12                          // _cfa_c
)
{// addr = 0x08048600
    intOrPtr _v36;                         // _cfa_ffffffdc
    intOrPtr _v40;                         // _cfa_ffffffd8
    _unknown_ __ebx;                       // r1
    _unknown_ __edi;                       // r4
    signed int __esi;                      // r5
    _unknown_ __ebp;                       // r6
    _unknown_ _t14;                        // _t14
    _unknown_ _t15;                        // _t15
    signed int _t18;                       // _t18

    __i686.get_pc_thunk.bx();
    _t15 = _t14 + 4529;
    __esp = __esp - 28;
    _init();
    _t18 = _t15 + -248 - _t15 + -248 >> 2;
    if(_t18 == 0) {
    } else {
        __esi = 0;
        do {
            _v36 = _a12;
            _v40 = _a8;
             *__esp = _a4;
             *((intOrPtr*)(_t15 + -248 + __esi * 4))();
            __esi = __esi + 1;
        } while(__esi < _t18);
    }
    __esp = __esp + 28;
    return;
}

__i686.get_pc_thunk.bx()
{// addr = 0x0804865A
    return;
}

__do_global_ctors_aux()
{// addr = 0x08048660
    intOrPtr* __ebx;                       // r1
    _unknown_ __ebp;                       // r6

    __eax = __CTOR_LIST__;
    if(__eax == 255) {
    } else {
        __ebx =  &__CTOR_LIST__;
        asm("o16 nop ");
        do {
            __ebx = __ebx - 4;
             *__eax();
            __eax =  *__ebx;
        } while(__eax != 255);
    }
    return;
}

_fini()
{// addr = 0x0804868C
    _unknown_ __ebx;                       // r1
    _unknown_ __ebp;                       // r6
    _unknown_ _t1;                         // _t1

    __esp = __esp - 4;
    L1();
    _pop(__ebx);
    __do_global_dtors_aux(__esi);
    _pop(__ecx);
    return;
}

L08048698()
{
    _unknown_ _t1;                         // _t1

    _pop(__ebx);
    __do_global_dtors_aux(__esi);
    _pop(__ecx);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

L08048698()
{
    _unknown_ _t1;                         // _t1

    _pop(__ebx);
    @rec __do_global_dtors_aux@__do_global_dtors_aux@(__esi);
    _pop(__ecx);
    _pop(__ebx);
    __esp = __ebp;
    _pop(__ebp);
    return;
}

// Statistics:
//      74 Register nodes
//      35 Temporaries nodes
//       5 Casts
//     207 Statements
//       2 Labels
//       1 Gotos
//      17 Blocks
//     469 Nodes
//      10 Assembly nodes
//      27 Unknown Types


Total time: 0 seconds.


Структура программы (вначале) в общем несколько лучше, чем у Boomerang, и куда больше подробностей.



2. Бен, ай нид хелп: MEX-файл, написанный на C  + BLAS, исходников которому нет.
Этот пример в посте приводить не стану, так как он длинный, но желающим попробовать своё декомпиляйшн-кунфу такая возможность предоставится:
Некоторые входные данные: это оптимизационный алгоритм для Quadratic Programming типа Branch-and-Bound (почитать тут и здесь). Алгоритм в целом прост и незатейлив, но самая сложная часть в нём - определить lower/upper bound через решение упрощённой оптимизационной задачи, и делать это быстро. Как такое сделать - хороший вопрос, и именно он меня интересует более всего. 

Короче, важен не столько алгоритм, сколько его составные компоненты (стратегия и подпрограммы для lower bound estimation).

Автор этих строк, поковыряв выхлоп RecStudio, нашёл для себя подсказку на строчке 12319:
qps_mq_sub( .....

и особенно на строчке 12088:
getalp( ....
что позволило автору предположить, что для lower/upper bounds  использутеся Liner Programming.  Не слишком много, но по крайней мере понятно, в какую сторону копать.

Если у кого-то вдруг проявится желание потыкать в оный бинарник палочкой, IDA Pro и ещё чем - не стесняйтесь отписываться в комментариях.
Обновление: теперь можно сравнить выдачи Boomerang, RecStudio, и (спасибо, Григорий!) IDA Pro. В самом деле, выдача IDA Pro куда лучше того, что дают остальные, особенно boomerang. Можно выудить (до некоторой степени) структуру программы и даже сообщения об ошибках.


Ссылки
Интересующийся читатель может попробовать полистать вебстраницы автора RecStudio с полезной информацией, сходить на wiki-ресурс по обратной разработке.

Помимо познавательных диссертаций Michael James Van Emmerik (Boomerang) и Cristina Cifuentes [C. Cifuentes, Reverse Compilation Techniques], есть хорошие книжки по теме:
  • "Compilers - Principles, Techniques and Tools", Aho, Sethi, Ullman, 1986 Addison-Wesley Publishing Co.  ISBN 0-201-10088-6.
  • "Advanced Compiler Design & Implementation", Steven Muchnick, 1997 Morgan Kaufmann Publishers, ISBN 1-55860-320-4.
  • "How debuggers work - Algorithms, Data Structures, and Architecture", Jonathan Rosemberg, 1996 John Wiley and Sons, ISBN 0-471-14966-7.

Дело это интересное, но весьма утомительное, хотя может помочь при раскопках очередного legacy-software и сэкономить вам полжизни.

19 комментариев: |высказаться!| RSS-лента дискуссии.|
redVi комментирует...

Отличный пост, спасибо. Для практического применения мне пока без надобности (куда уж нам, самоучкам-недопрограммерам), но всё может пригодиться.

Unknown комментирует...

Пост - как украсть чужой алгоритм. Уж да...

virens комментирует...

@redVi комментирует...
Отличный пост, спасибо.
Пожалуйста. Мне просто по нужде пришлось разбираться со всем этим. Я так понял, что пока никто не отважился декомпилировать приведённый в посте файл... Придётся его писать самому :-(

Для практического применения мне пока без надобности
И хорошо, если б не пригодилось. Выуживать из этого месива алгоритм - дело безблагодатное.


@Serge Ku комментирует...
Пост - как украсть чужой алгоритм.
Сергей, это не совсем так. В моём случае, по крайней мере. Проблема в том, что мы все на факультете используем эти алгоритмы для работы (мы - инженеры, а не математики). И этот мерзавец потратил 7 лет для их создания и отладки. А потом взял и свалил, не оставив никому исходников. Даже описания алгоритмов пришлось выуживать из его статей.

Как бы это помягче сказать, джентельмены так не делают. Зато у меня есть шанс отличиться и сделать алгоритм лучше. Что я сейчас и пытаюсь сделать. Так что если в скором времени тут начнут появляться посты по хардкорному Сишному программированию мозговыносящих алгоритмов - не стоит удивляться :-)

Iskander комментирует...

@redVi
куда уж нам, самоучкам-недопрограммерам
А что бывают другие? Покажи мне ВУЗ где обучают чему-то дельному в этой части, а не просто куски паттернов+Дельфи, в лучшем случае кусок C++... Единственным исключением из правил считаю Академический университет в Питере, там и правда учат дельному, но там магистратура. (правда КАКАЯ!)
@virens
Так что если в скором времени тут начнут появляться посты по хардкорному Сишному программированию мозговыносящих алгоритмов
... мы будем оченна рады...

virens комментирует...

@Iskander комментирует...
А что бывают другие? Покажи мне ВУЗ
Вообще-то это оффтопик, от которого стоит воздержаться всем участникам, но тем не менее.

Другие - бывают, но это не задача ВУЗа (университета) выпускать coding monkeys. В университете прививают и развивают абстрактное логическое мышление - в хороших университетах к этому идут прикладные курсы, показывающие, как всё это использовать. А не просто бубнят тервер Чистякова или линейную алгебру Кострикина-Манина родом из 50-х годов.

Coding monkeys готовят в ПТУ, или как тут их политкорректно называют, Institutes (TAFE in Australia). Типичные курсы программирования выглядят вот так... эээ... ну или вот так. Ну да, программирование apps для айфона, Джава (с аутентичным индийским раджой в качестве препода), и вёб-дизайн.

Есть отличие: обезьяны не придумают новый алгоритм или очередную инновацию - это просто исполнители.

мы будем оченна рады...
Мне тут просто пришлось разбираться с MEX-файлами в МАТЛАБ, и я с удивлением обнаружил, что документации по этому поводу с гулькин хвост. А там есть где наступить на грабли.

Iskander комментирует...

Есть отличие: обезьяны не придумают новый алгоритм или очередную инновацию - это просто исполнители.
Толи я чего не понимаю толи computer science как раз этому и учит Да и software engineering тут тоже не лыком шиты. Так что зря Вы так Михаил, ежели кому нужны "monkey" их нанимают в Индии и не заморачиваются...

Vlsu комментирует...

@virens

Пост довольно полезный, но я так до конца и не понял, как сейчас обстоят дела с C++?

Пару лет назад вставала такая задача, но все попытки декомпилировать виндовый exe-шник ничем хорошим не увенчалась.

Вот как обстояли дела: я практиковался с C++ и написал в Visual Studio простенькое консольное приложение (тест по физике с выдачей оценки в конце). Так вот, ради интереса решил его декомпилировать. Все пробы выдавали ОГРОМНОЕ месиво, в котором совершенно не понятно, кто что делает. Хотя переменных было не много, пара формул, пара условий и один цикл...


А там есть где наступить на грабли.

Будем с нетерпением ждать продолжение!


Вообще-то это оффтопик, от которого стоит воздержаться всем участникам, но тем не менее

Здесь есть такие участники, которых очень трудно сдерживать :-)
И да, это ещё хорошо, что нет холивара Python vs C++, который присущ почти любому посту про программирование


@Iskander

где обучают чему-то дельному в этой части, а не просто куски паттернов+Дельфи, в лучшем случае кусок C++

Что-то дельное - это опыт, умение мыслить и создавать своё. Этому и учат в ВУЗах.

Начну издалека: в школе учат программированию на паскале. Пример цикла: "for i:=1 to n do". Для будущего программиста не важен вид этой строки для определённого языка программирования, а важно то, что с его помощью можно сделать. Если программист научится моделировать ситуацию в уме, то сможет описать её на любом языке программирования. Найдёт, что в C++ приведённый цикл выглядит следующим образом: "for (i=0; i<n; i++)"...

Так что нужно выбирать самому, кем становиться: "творцом нового" или "наборщиком шаблонов"

virens комментирует...

@Iskander комментирует...
Толи я чего не понимаю толи computer science как раз этому и учит
Computer science учит придумывать новое и для этого люто пичкает теорией. В хороших университетах это добавляют практикой, но в век cost-cutting и прочих dirt-cheap практики становится больше, а теории - меньше. Это приводит к тому, что многие под computer science понимают кодинг. Это неправильно в корне, но как можно безграмотным Джонам До объяснить, что теория важна?

Да и software engineering тут тоже не лыком шиты.
Эти сползают в coding monkey ещё более стремительными темпами. Не говоря о том, что они забиты выпускниками индийских богаделен и прочими жрецами джавы.

кому нужны "monkey" их нанимают в Индии и не заморачиваются...
Искандер, ты просто никогда не видел результат их деятельности. Те, что приезжают сюда на postgraduate study и занимаются телекомом (а чем же ещё?!) - просто кошмарны. Никакой мысли outside the box, вообще. Плюс то, что они меня часто спрашивают по линейной алгебре и терверу... это леденящий душу невыразимый ужас. И они пишут научные статьи!

@Vlsu комментирует...
как сейчас обстоят дела с C++?
Я не знаю, и мне это мало интересно. Меня огорчают попытки воткнуть плюсы везде и всюду, даже где они не нужны совсем. Пример: один деятель написал quadprog++ (это Dual Active-set optimization, Goldfarb-Idnani algorithm).

Так вот, это всего лишь один алгоритм, и на Си это занимает 30-40 килобайт исходников (я пишу похожий, так что примерно так выходит). Вместо этого мы имеем 630 килобайт (!) всякого плюсатого говна с шаблонами, классами и прочими мигалками, которые только усложняют чтение и без того мозголомного кода.

У меня только один вопрос: зачем?!

я практиковался с C++ и написал в Visual Studio простенькое консольное приложение... решил его декомпилировать. Все пробы выдавали ОГРОМНОЕ месиво

Собственно, выше пример как раз из той же серии. Декомпиляторые не выдадут тебе обратно чистенький и незаплёванный код. Будет здорово, если ты вообще выудишь оттуда хотя бы структуру программы или какие-то намёки (как удалось это мне).

И да, это ещё хорошо, что нет холивара Python vs C++
А какой тут может быть холивар?

c++ compatibility issues problems - более 3 миллионов совпадений.


python upgrade transition pain in the ass
- почти миллион совпадений.

Любителям Руби-на-рельсах.

Какие холивары могут быть там, где никто не думает об обратной совместимости хотя бы нескольких последних версий?!

Что-то дельное - это опыт, умение мыслить и создавать своё. Этому и учат в ВУЗах.
Vlsu, ты отчасти прав: учат мыслить абстрактно и пытаться понять, как оно всё устроено.

Если программист научится моделировать ситуацию в уме
Собственно, это и есть образование: научить человека мыслить моделями. А не просто подставлять числа в формулы. Увы, но последнее появляется всё больше и больше, причём даже в университетах.



По теме поста: Vlsu и Iskander, как насчёт попробовать декомпилировать линуксовый экзешник в посте? Оно в общем представляет интерес.

Анонимный комментирует...

По-моему проще асм читать, чем тот ужас, который выдает recstudio...

Iskander комментирует...

Уффф, ничего себе мне тут лекцию начитали!
Так попорядку:
@Vlsu
По-моему приведенный Вами кусок на Паскале не соответствует по смыслу куску на Сях... (В Паскале ведь, если мне память не изменят 0!=1)?
@virens
Computer science учит придумывать новое и для этого люто пичкает теорией.
И поэтому существование такого в родной стране меня дико удивило, там действительно люто, бешено пичкают теорией!
В хороших университетах это добавляют практикой
И этому я тоже удивился, ибо практики там тоже хватает...
всякого плюсатого говна с шаблонами, классами и прочими мигалками
Ну вот полегче, потоньше как-то надо...
учат мыслить абстрактно
Иногда уж слишком абстрактно...
научить человека мыслить моделями
Еслиб еще был предмет который учит не просто решать кучу интегралов, и абстрактных задач по терверу (о дааа задачи про кучу шаров или 100500 выстрелов наверное именно такая абстракция должна мне приходить в голову) или мат статистике (привет расчетная методичка состоящая целиком из цифр...)
Так я о чем собсна... А так вот еслиб в дополнение ПОДЧЕРКИВАЮ в ДОПОЛНЕНИЕ к теории давали еще и теорию составления мат моделей на примере... да хоть на каком-то более или менее реальном примере... ну жить бы стало лучше... жить бы стало веселее как говорил Иосиф Виссарионович...
декомпилировать линуксовый экзешник в посте
Разгребусь с сессией и попробую, большего сказать не могу (правда сомневаюсь что gcc-шный декомпилированый код будет по степени заговненности сильно лучше кода Visual Studio)
P.S. Автору поста хорошая новость под новый год E17... РЕЛИЗНУЛАСЬ! Ждем новогоднего поста от автора о впечатлениях!

Gregory комментирует...

Я правильно понимаю, что Вы воспользоваться пиратским IDA Pro не можете в данном случае? А прислать декомпиленный с её помощью код можно? Потому что он гораздо лучше того ужаса, который выдают Boomerang и RecStudio для этого mex'a

virens комментирует...

@lierdakil комментирует...

По-моему проще асм читать, чем тот ужас, который выдает recstudio...

Асм читать как раз и не хочется, потому как хочется выудить структуру алгоритма. Он довольно сложный, то есть это не просто перемножение пары матриц.


@Iskander комментирует...

Это оффтопик. Мой посыл был в том, что программирование и code monkeys != computer science. Об этом многие не знают и путают их. Отличие в том, что один из них умеет мыслить абстрактно, а другой - нет. И этому нельзя научить - это можно развить, до определённой степени.

всякого плюсатого говна с шаблонами, классами и прочими мигалками
Ну вот полегче, потоньше как-то надо...


Тоньше не получается: мне не хотелось тратить время на реализацию этого алгоритма - я знаю, как он работает, и мне хотелось взять готовый код и его кастомизировать. И я не понимаю, зачем разводить всю эту хреновину ради ОДНОГО алгоритма, который на Си занимает пару сотен строчек кода.

абстрактных задач по терверу
Стивен Кай спасёт отца русской демократии. Без шуток и иронии - это один из лучших учебников по прикладной теории вероятности. Я сам его почитываю время от времени.

P.S. Автору поста хорошая новость под новый год E17... РЕЛИЗНУЛАСЬ!
Да я уж видел. Конец света близок, как никогда - такие вещи просто так не релизят :-)

Ждем новогоднего поста от автора о впечатлениях!
Тут у нас жарко, лето и совсем ничего не хочется делать. Но я попробую :-)


Искандер, завязывай с оффтопом. Давай лучше письмом напиши.

Вообще, если нужны хорошие книжки по терверу и линейной алгебре - обращайся, но учти: мои книги - только на английском.

virens комментирует...

@Gregory комментирует...
Я правильно понимаю, что Вы воспользоваться пиратским IDA Pro не можете в данном случае?

Мне религия не позволяет :-)

А прислать декомпиленный с её помощью код можно?

Конечно! Можно выложить на http://pastebin.com/ или прислать мне на почту mydebianblog@gmail.ком, буду благодарен.

Потому что он гораздо лучше того ужаса, который выдают Boomerang и RecStudio для этого mex'a

У меня IDA Pro нет (и не предвидится), так что был бы очень рад посмотреть на его результаты.

Gregory комментирует...

Virens, отправил исходник Вам на почту

virens комментирует...

@Gregory комментирует...
Virens, отправил исходник Вам на почту
Да, спасибо, только что получил.

Результат в самом деле лучше того, что выдаёт бумеранг и RecStudio.

Самая большая проблема в том, что бинарник содержит вызовы библиотечных фукнций из BLAS, и, что понятно, декомпилятор выдаёт содержимое этих функций. BLAS-то у меня есть, и не особенно нужен, а вот ход и структура алгоритма интересны больше.

Огромное спасибо за исходник - у меня IDA Pro нет, а посмотреть на его работу очень хотелось. По всему видно, что народная молва про IDA Pro не врёт - результат в самом деле на голову выше конкурентов.

Анонимный комментирует...

Подскажите, пожалуйста, где можно найти специалиста по декомпляции библиотек.
Надо разобрать структуру одной функции, но к сожалению ни код Асма ни запутанный сырой код на декомпильованом С не дает разобраться в работе библиотеки.
Где можно найти фрилансера, что подаст метод на блюдечке с синей каемочкой? Среди тегов на фриланс нету скила декомпиляция :)

Анонимный комментирует...

There is an interesting Russian project (not decompiler, but restorer of binary code algorithms). It's in the initial state, but some examples already works!
http://demono.ru

The site has an online-service for recovery algorithms of code at the PowerPC- assembler.
I recommend to look.
http://demono.ru/Online/online.html

Анонимный комментирует...

вот интересный проект (в зародыше правда) с опубликованными статьями по нему
http://demono.ru
есть кстати онлайн-сервис восстановления кода для PowerPC и рабочими примерами - можно поиграться

Анонимный комментирует...

а как декампелировать ехе написанный для мс доса. есть ли варианты?

Отправить комментарий

Подписаться на RSS-ленту комментариев к этому посту.