Проблема восстановления исходного кода из скомпилированных бинарников возникает сравнительно часто и протекает остро, с воем и рыданиями. Здесь нам, до некоторой степени, помогут замечательные 
программы-декомпиляторы, и в этом посте автор собрал свои скромные попытки выдрать исходники (или хотя бы намёки на них) из скомпилированных из 
С-шного кода бинарников.
Задача для декомпилятора бинарников, собранных из С кода:
Классический случай: один деятель на факультете написал на правильном 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 и сэкономить вам полжизни.