четверг, 30 марта 2017 г.

The Origin of Modern Arithmetic


http://wormholetravel.net/

We shall understand "arithmetic" in the sense of the Greek arithmetica. Equivalents are "the higher arithmetic" and the "theory of numbers". Gauss, the fore­most exponent of the classical theory after Fermat, preferred the simpler "arithmetic" or the longest "higher arithmetic". Modern arithmetic began with Fermat, roughly in the period of 1630-65. Significant as was Fermat's work in other fields of maths, he is usually considered to have made his greatest and most personal contribution in arithmetic.
This extensive division of maths differs from others in its lack of general methods. Even comprehensive theorems here are more difficult to devise than, say, in algebra or analysis. Thus, in algebra there is a complete theory of the solution of algebraic equations in one unknown; in fact, there are two complete theories. In arithmetic the simplest corresponding problem is the solution in integers of equations in two unknowns with integer coefficients, and for this there is nothing approaching a complete theory.
Many of Fermat's discoveries were either recorded as marginal notes in his books (the arithmetic in his copy of Diophantus) or were communicated usually without proof to correspondents. Some of his theorems were proposed by him as challenge problems to the English mathematicians. For example, he demanded a proof that the only positive integer solution of  x2 + 2 = y3 is x=5, y=3. It will suffice to state those two of Fermat's discoveries which have had the profoundest influence on arithmetic and algebra since his time, and the one general method in arithmetic due to him.
Fermat stated that if n is a positive integer not divisible by the positive prime p, then np-1 is divisible by p. The Chinese "seem to have known as early as 500 B.C. "the special case n = 2. Any student of the theory of algebraic equations, or of modern algebra, or of arithmetic, will recall the frequent appearance of this fundamental theorem. The first published proof was Euler's in 1738; Leibnitz had obtained a proof before 1683 but did not publish it. The rule of priority in maths is first publication.
The second famous assertion of Fermat, his celebrated "last theorem", states that xn + yn = zn, xyz ≠ 0, n > 2 is impossible in integers x, y, z, n. He claimed (1637) to have discovered a marvelous proof; and whether or not he had, no proof has yet been found. There seems to be but little point now in proving the theorem for special n's, enough in that direction being known to make it fairly plausible that the theorem is true.
But, to take out insurance against a possible disproof tomorrow, it must be emphasized that arithmetic is the last place in maths where unsubstantiated guessing is either ethical or profitable. Numerical evidence counts for very little; the only luxury reputable arithmetician allows himself is proof. It is generally agreed that the famous "last theorem", true or false, is of but slight interest today. But its importance in the development of arithmetic and modern algebra has been very great.
Fermat's general method, that of "infinite descent", is profoundly ingenious but has the disadvantage that it is often extremely difficult to apply. In the particular theorem for which Fermat invented the method, it is required to prove that the very positive prime of the form 4n + 1 is a sum of two integer squares. But 5 = 12 + 22; hence the theorem.
The  outstanding desideratum in arithmetic is the invention of general methods applicable to nontrivial types of problems. Further, the arithmetical solution of a problem should consist in prescribing a finite number of purely arithmetical operations (exempt from all tentative processes) by which all the numbers satisfying the conditions of the problem, and those only, are obtained. Nobody after Euclide and before Lagrange, in the eighteenth century even distantly approached this ideal.

Многие понятия, задачи и методы теории чисел пришли к нам из древности; от древних греков, китайцев, вавилонян, египтян. Об их происхождении говорят сохранившиеся до наших дней названия: алгоритм Евклида, способ решета Эратосфена, пифагоровы треугольники, диофантов анализ, египетские дроби и т.д. Знакомство с арабскими рукописями и латинскими переводами Евклида и Диофанта в средние века пробудило у европейцев интерес к задачам теории чисел. Наибольший интерес представляют теоретико-численные результаты.
П. Ферма. Основные открытия Ферма по теории чисел содержатся в его замечаниях в книге Диофанта и в его письмах к ряду европейских математиков. Наибольшей известностью в теории чисел пользуются «малая теорема Ферма» (ap-1 = kp + 1) и «последняя» или «великая теорема Ферма" (xn + yn = zn ) Это уравнение не имеет решений в целых числах при n целом, большем чем 2. Хотя сочинения Ферма были изданы через несколько лет после его смерти, они не привлекли в то время особого внимания математиков.
Л.Эйлер — один из творцов дифференциального и интегрального исчисления, продолжатель исследований Ньютона и Лейбница. Его любимым предметом была теория чисел. Поэтому не удивительно, что именно у Эйлера возникла мысль применить в теории чисел методы математического анализа. Много сделал для теории чисел современник Эйлера Ж.Лаграж.. Ему принадлежит первое доказательство теоремы о четырех квадратах, важные исследования по теории квадратичных форм, полное решение уравнения Ферма x2ay2 = 1  и другие важные результаты.
Первый систематический  курс теории чисел был опубликован А.Лежандром, в котором он изложил результаты Эйлера, Лагранжа и свои собственные. Вслед за ним появился капитальный и оригинальный труд К.Гаусса "Арифметические исследования», успешно применившего теорию чисел к теоретическому решению древней задачи о построении правильного семнадцатиугольника с помощью циркуля и линейки. Гаусс взглянул на теорию числе с новой точки зрения, стараясь в ее построении придерживаться единого принципа. Наследником и продолжателем Эйлера, Лагранжа и Гаусса в теории чисел явился ПЛежен-Дирихле, который доказал справедливость великой теоремы Ферма для n = 14. Он же впервые доказал теорему об арифметических прогрессиях. Другая большая заслуга Дирихле состоит в изучении им асимптотических законов для теоретико-числовых функций.

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

вторник, 28 марта 2017 г.

The Arithmetization of Classical Mathematics



http://wormholetravel.net/
We have had occasion to refer to the notion of a "model" or an "interpreta­tion" of a math theory constructed with the help of another theory. This is not a recent idea, and it should undoubtedly be seen as a continually recurring mani­festation of a deep-lying feeling of the unity of the various "math sciences". If the traditional maxim "All things are numbers" of the early Pythagoreans is tak­en as authentic, it may be considered as the vestige of a first attempt to reduce the geometry and algebra of the time to arithmetic.
The increasingly widespread use of the notion of "model" was to permit the nineteenth-century mathematicians to achieve the unification of maths dreamed of by the Pythagoreans. At the beginning of the century, whole numbers and continuous quantities were as irreconcilable as they had been in antiquity; the real numbers were related to the notion of geometric magnitude (especially that of length), and the "models" of negative numbers and imaginary number! were constructed on this basis. Even the rational numbers were traditionally associated with the idea of "subdivision" of magnitude into equal parts. Only the integers remained apart, as "exclusive products of our intellect", as Gauss said in 1832.
The first attempts to bring together arithmetic and analysis were concerned with the rational numbers (positive and negative); they were taken up around 1860 by several authors, notably Grassman, Hankel, and Weierstrass. To Weierstrass is, apparently, due the idea of obtaining a "model" of the positive of negative rational numbers by considering classes of ordered pairs of natural integers. But the most important step still remained to be taken, namely, to construct a "model"  of the irrational numbers from within the theory of rational numbers.
By 1870 this had become an urgent problem because of the necessity, after the discovery of "pathological"  phenomena in analysis, to purge every trace of geometrical intuition and the vague notion of "magnitude" from the definition of real numbers. The problem was, in fact, solved at about this time almost simultaneously Cantor, Dedekind, Meray and Weierstrass, using quite different methods from one another.
From then on, the integers became the foundation of all classical maths. Furthermore,  the "models" founded on arithmetic acquired still greater importance with the extension of the axiomatic method and the conception of math objects as free creations of the human intellect. For there remained a limitation to the freedom claimed by Cantor, namely, the limitation raised by the question of "existence " which had already occupied the Greeks, and which arose now so much  more  urgently precisely because all appeal to intuitive representation was now abondoned.
We shall not discuss what a philosophico-math maelstrom was to be generated by notion of "existence" in the early years of the twentieth century. But in the  nineteenth century this stage had not yet been reached, and to prove the existence of a math object having a given set of properties meant simply, just as Euclid, "to construct" an object with the required properties. This was purpose of the arithmetical "models".

Once the real numbers had been "interpreted" in terms of integers, then the same was done for complex numbers and Euclidean geometry, thanks to analytic geometry, and likewise for all the new algebraic objects introduced since the beginning' of the century. Finally, in a discovery which achieved great fame Beltrami and Klein obtained Euclidean "models" of the non-Euclidean geometries of Lobachevsky and Riemann and thereby "arithmetized" (and completely justified) these theories which at first had aroused so much distrust.

среда, 22 марта 2017 г.

Введение в Си и начало reverse engineering.



Урок 1 Введение в Си и начало reverse engineering.
/*Это моя первая программа на С. Я создаю исходные код. Далее использую компилятор, который мой исходный код превращает в объектный код. После идет подключение компоновщика, который компонует исходный код, библиотечный код и код запуска. Только после этого получается исполняемый код.
Из ООП мы знаем, что переменная - это коробочка, куда мы складываем типы данных. Функция преобразует наши типы входных данных, и на выходе мы получаем модифицированные переменные
Компьютерная программа выражена в числовом коде - машинный код. Все что хранится в компьютере, хранится в виде чисел. */

Введем понятие ПЕРЕМЕННАЯ

Понять, что такое переменные, поможет простая метафора. Думайте о них как о небольших (или больших) спичечных коробках! Именно как о спичечных коробках, которые вы раскрасили и на которых написали некие имена.


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

Чтобы узнать о содержимом коробка, его нужно просто открыть и посчитать бусины.
Массивы можно представить в виде нескольких склеенных вместе спичечных коробков.


//БУФЕР - ПРОМЕЖУТОЧНАЯ ОБЛАСТЬ ХРАНЕНИЯ

//Это простая программа
 #include <stdio.h>                          
int main(void)                                  
{                                                        
            int num;                                
            num = 1;                               
            printf("Я простой");             
            printf("компьютер. \n");                                                                                                                            printf("Моя любимая цифра %d, так как она первая.n", num);                   
             return 0;          
            }
 Пояснения
#include <stdio.h>    //Начало программы. Включить другой файл
/*Эта строка требует от компилятора включить информацию, хранящуюся в файле stdio.h, который является стандартной частью всех пакетов компилятора языка С. Этот файл обеспечивает поддержку ввода с клавиатуры и отображения вывода.
include - Директива включить файлы - способ совместного использования информации, который применяется во многих программах.
#include - директива прeпроцессора в С. В общем случае компиляторы языка С выполняют некоторую подготовительную работу над исходным кодом перед компиляцией - это называется предварительная обработка.
Файл stdio.h поставляется как часть всех пакетов компиляторов С. Он содержит информацию о функциях ввода и вывода, таких как printf(),  и предназначен для использования компилятором, это заголовочный файл стандартного ввода-вывода.
Описание функции printf() требует использования файла stdio.h. Это относится к библиотечным функциям.
stdio.h - заголовочный файл
# - символ обозначает, что эта строка должна обрабатываться препроцессором до передачи ее компилятору. */
int main(void)            //имя функции (объявление функции с именем main
/*Программа на С состоит из одной или большего числа функций - базовых модулей программ на С. Рассматриваемая программа состоит из одной функции с именем main.
Круглые скобки показывают, что main() есть имя функции,
int - указывает на то, что функция main() возвращает целое число,
void - говорит о том, что функция main() не принимает никаких аргументов.
Программа на языке С всегда начинается с выполнения функции main().
() - идентификация функции - т.е. main()  - скобки идентифицируют main()  как функцию.
Функции - это базовые модули программы на языке С.
int - это возвращаемый тип функции main(). Это значит, что тип значения, который может вернуть функция main(), является целочисленным.
В круглых скобках, которые следуют за именем функции, находится информация, передаваемая функциями. В данном примере ничего не передается, поэтому в скобках содержится слово void.

{
            .....
}                      - фигурные скобки определяют границы функции main().
*/

{}                     //тела функции. Оператор определения функции

int num;         //ОПЕРАТОР ОБЪЯВЛЕНИЯ назначает переменной имя и определяет тип данных,                     которые будут храниться в этой переменной.
/*этот оператор объявляет переменную с именем num и уведомляет, что переменная num имеет тип int (целое число).  Также можно сказать, что где-то в функции имеется переменная по имени num. И переменная имеет целочисленный тип.
В данном примере объявлены два объекта ->
num - переменная в теле функции
int - объявляет num как целое число, т.е. число без десятичной точки или без дробной части. (int - это тип данных). Также является ключевым словом.
; точка с запятой в конце строки показывает, что данная строка является оператором
num - является идентификатором, имя переменной, функции, логического объекта
Объявление переменной соединяет конкретный идентификатор с конкретной ячейкой в памяти компьютера и при этом устанавливает тип информации или тип данных, которые будут храниться в этой ячейки.
В роли КОНСТАНТ выступают целые числа.
*/
num = 1;        //ОПЕРАТОР ПРИСВАИВАНИЯ - устанавливает значение переменной или область                   хранения.
/* Оператор num = 1; присваивает значение 1 переменной с именем num. Присвоить значение 1 переменной num. 
int num; - резервирует в памяти компьютера пространство для хранения переменной num, а строка с оператором присваивания записывает значение в эту ячейку. Позже можно присвоить переменной num другое значение. Вот почему num называется переменной.
num - ИМЯ ПЕРЕМЕННОЙ
1-> КОНСТАНТА
*/
АРГУМЕНТ - ЭЛЕМЕНТЫ ИНФОРМАЦИИ, ПЕРЕДАВАЕМОЙ ФУНКЦИИ.
ФУНКЦИИ printf() и  scanf() не ограничены конкретным количеством аргументов.
Аргументы отделяются друг от друга запятыми.
printf("Я простой");          //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ - запускает на выполнение функцию                                    с указанным именем
/*Первый оператор, использующий функции printf() отображает на экране фразу "Я простой", оставляя курсор в той же строке. Используя здесь функцию printf() является частью стандартной библиотеки С. Она носит название функции, а использование функции в программе называется вызовом функции.
Программа выполняется последовательно. Когда доходит до строки printf("Я простой"); управление передается указанной функции printf(). Как только функция выполнит свою задачу, управление возвращается в исходную, т.е. в вызывающую функцию, в данном примере - main().
printf() - функция с именем printf(). Информация в круглых скобках - это информация, передаваемая из функции main()  в функцию printf().
Эта строка передает функции printf() фразу "Я простой" - эта информация называется аргументом, т.е. аргумент функции.
Что делает Функция printf() с этим аргументом? Просматривает все что  заключено в двойные кавычки "" и выводит этот текст на экран.
*/
printf("компьютер. \n");   //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ - запускает на выполнение функцию с указанным именем 
/*Следующий вызов функции printf() приписывает слово компьютер в конец напечатанной предыдущей фразы. \n - это код, указывающий компьютеру начать новую строку, т.е. переместить курсор в начало следующей строки*/
printf("Моя любимая цифра %d, так как она первая \n", num);
/*Последнее использование функции printf() приводит к печати значения переменной num(которое равно 1), вставленной во фразу, заключенную в кавычки. Код %d указывает компьютеру, где и в какой форме печатать значение num */
return 0; //ОПЕРАТОР ВОЗВРАТА

printf()            - ФУНКЦИЯ ВЫВОДА
scanf() - ФУНКЦИЯ ВВОДА
printf() - функция вывода, применяется для вывода фраз и значений переменных
scanf() - функция ввода - воспринимает ввод аналогично getchar() но при помощи спецификаторов преобразования, преобразует символьный ввод в числовые значения
getchar() - функция ввода аналогична scanf() только интерпретирует каждый байт как символьный код
putchar() - функция вывода аналогично printf()

Теперь, после ознакомления с конкретным примером, вы готовы к изучению нескольких общих правил написания программ на языке С. Программа состоит из совокупности одной или нескольких функций, одна из которых обязательно должна быть названа main (). Написание функции состоит из заголовка и тела функции. Заголовок содержит операторы препроцессора, такие как #include , а также имя функции. Вы можете распознать имя функции по круглым скобкам, внутри которых может быть пусто. Тело функции заключено в фигурные скобки ( { } ) и состоит из некоторой последовательности операторов, при этом каждый оператор завершается точкой с запятой.



МНОЖЕСТВО ФУНКЦИЙ
Продемонстрируем возможность внедрения в программу наряду с функцией main() вашей собственной функции.

Пример
#include <stdio.h>                 //КОМАНДА ПРЕПРОЦЕССОРА - подключение файла                                                                     стандартной библиотеки С stdio.h содержит библиотеку функций                                                    ввода-вывода

void jolly(void);                     //Объявления ПРОТОТИП ФУНКЦИИ с именем jolly()
void deny(void);                    //Объявления ПРОТОТИП ФУНКЦИИ с именем deny()
int main(void)                        //ИМЯ ФУНКЦИИ С АРГУМЕНТАМИ. Имя функции - main().                                                        Функция которой всегда присутствует в программе на С.           
                                               //int - ф-ция возвращает целое число, void - ф-ция не принимает                                                  аргументов
{
printf ("He is funny good guy. \n");               //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ с именем printf()                                                                           функция ВЫВОД ДАННЫХ НА ЭКРАН.
      jolly();                                                      //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ с именем  jolly() -                                                                       это  ПРОТОТИП ФУНКЦИИ
      printf("He is funny good guy. \n");
      deny();                                                  //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ с именем  deny() -                                                                        это    ПРОТОТИП ФУНКЦИИ
      return 0;                                               //ОПЕРАТОР ВОЗВРАТА
}
void jolly(void)                                             //начало определения функции с именем jolly,                                                                                    функция не  принимает аргументов и нечего не                                                                                  возвращает
{
printf("He is funny good guy. \n");              //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ с именем printf() -                                                                      функция ВЫВОД ДАННЫХ НА ЭКРАН. Имеет один                                                                      аргумент. АРГУМЕНТ - ЭЛЕМЕНТЫ                                                                                                  ИНФОРМАЦИИ,  ПЕРЕДАВАЕМОЙ ФУНКЦИИ.
}
void deny(void)                                            //начало определения функции с именем deny
{
 printf("Nobody say another \n");                 //ОПЕРАТОР ВЫЗОВА ФУНКЦИИ с именем printf() -                                                                        функция ВЫВОД ДАННЫХ НА ЭКРАН.
                                                                      //\n код указывающий начать новую строку
}

Функция butler () трижды появляется в рассматриваемой программе .
В первый раз она появляется в виде прототипа, передающего компилятору информацию о функциях, которые будут использованы в данной программе.
Во второй раз она появляется в main () в форме вызова функции.
Третий раз, в данной программе представлено определение функции, которое является исходным кодом самой функции. Рассмотрим по очереди каждое из этих трех появлений.

Прототип - это форма объявления, которая уведомляет компилятор о том, что вы используете конкретную функцию. Он также определяет свойства этой функции. Например, первое ключевое слово void в прототипе функции butler() указывает на то, что butler() не имеет возвращаемого значения .
(В общем случае функция может возвратить значение в вызывающую функцию для последующего его использования, но butler() этого не делает.)
Второе void, то, что в указано в функции butler (void) , означает, что функция butler() не принимает аргументов.
Поэтому, когда достигается место в main(), в котором вызывается butler(), выполняется проверка корректности использования функции butler(). Обратите внимание на тот факт, что ключевое слово void употребляется в смысле " пусто", а не в смысле "неправильно".

Исходный код
//Это простая программа
 #include <stdio.h>                          
int main(void)                                  
{                                                        
            int num;                                
            num = 1;                               
            printf("I am simple");             
            printf("computer. \n");                                                                                                                                printf("My love digit is  %das it is first", num);                   
             return 0;          
            }

Откроем Code Block
Далее создадим Новый проект - > Create New Project -> Console Application -> Выбираем Application на С -> Далее даем название проекту и место хранения -> Выбираем компилятор -> Finish -> Получаем заготовку, где можем писать свой код -> Пишем свой код. В нашем случае - наш пример
Далее Build and Run.
Мы получаем рабочее консольное приложение.
Теперь в картинках.
1) Открываем Code Blocks

2) Выбираем образ программы. В нашем случае Console Application


3) Выбираем язык на котором будем писать приложение. В нашем случае С. 
4) Даем название и путь хранения
5) Выбираем компилятор и нажимаем Finish
6) Получаем макет, где мы можем вставлять свой код 
7) Пишем свой код и нажимаем Build and Run
8) Получаем консольное приложение 

Анатомия программы на Си

Далее мы посмотрим нашу программу изнутри с помощью средств обратной разработки. Это поможет нам лучше понять анатомию программирования и работы ОС,
Классически мы используем:
- Hex Workshop Hex Editor - 16-ричный редактор
- PeiD - Один из самых популярных анализаторов исполняемых файлов. Хорошо определяет многие упаковщики и протекторы
- LordPe -  Инструмент для системных программистов которые нуждаются в ручном редактирование исполняемых файлов (Portable Executable).
- Ollydbg -   32-битный отладчик уровня ассемблера для операционных систем Windows, предназначенный для анализа и модификации откомпилированных исполняемых файлов и библиотек, работающих в режиме пользователя (ring-3).
- IDA Pro Disassembler (англ. Interactive DisAssembler) — интерактивный дизассемблер, который широко используется для реверс-инжиниринга.

Бит (русское обозначение: бит; международное: bit; от англ. binary digit — двоичное число; также игра слов: англ. bit — кусочек, частица) — единица измерения количества информации.

Целое, целочисленный тип данных (англ. Integer), в информатике — один из простейших и самых распространённых типов данных в языках программирования. Служит для представления целых чисел.

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

В программировании различают беззнаковые целые числа и целые числа со знаком. Знак числа обычно кодируется старшим битом машинного слова. Традиционно, если старший бит равен 1, то число считается отрицательным, только, если оно не определено как беззнаковое.

Количество чисел в машинном изображении множества целых чисел зависит от длины машинного слова, обычно выражаемой в битах. Например, при длине машинного слова 1 байт (8 бит) диапазон представимых целых чисел со знаком от -128 до 127. В беззнаковом формате байтовое представление числа будет от 0 до 255 (28 - 1). Если используется 32-разрядное машинное слово, то целое со знаком будет представлять значения от −2 147 483 648 (-231) до 2 147 483 647 (231−1); всего 1 0000 000016 (4 294 967 29610) возможных значений.

1 байт = 8 бит;
2 байт = 16 бит:
4 байт = 32 бит;
8 байт = 64 бит и т.д.

Многие языки программирования предлагают выбор между короткими (англ. short), длинными (англ. long) и целыми стандартной длины. Длина стандартного целого типа, как правило, совпадает с размером машинного слова на целевой платформе. Для 16-разрядных операционных систем — этот тип (int) составляет 2 байта и совпадает с типом short int (можно использовать как short, опуская слово int), для 32-разрядных операционных систем он будет равен 4 байтам и совпадает с длинным целым long int (можно использовать как long, опуская слово int), и в этом случае будет составлять 4 байта. Короткое целое short int, для 16-разрядных операционных систем, 32-разрядных операционных систем, и для большинства 64-разрядных операционных систем составляет — 2 байта. Также в некоторых языках может использоваться тип данных двойное длинное long long, который составляет 8 байт.

Анализ программы example.exe - 32-битное консольное приложение

1. Hex Workshop Hex Editor - 16-ричный редактор
Загрузим нашу программу в Hex Workshop Hex Editor

Теперь мы видим внутренности программы 

Здесь мы видим сигнатуру файла. Давайте разбираться дальше.

Магическое число, или сигнатура — целочисленная константа, используемая для однозначной идентификации ресурса или данных. Такое число само по себе не несёт никакого смысла и может вызвать недоумение, встретившись в коде программы без соответствующего контекста или комментария, при этом попытка изменить его на другое, даже близкое по значению, может привести к абсолютно непредсказуемым последствиям. По этой причине подобные числа были иронично названы магическими. В настоящее время это название прочно закрепилось как термин.

Portable Executable (PE, «переносимый исполняемый») — формат исполняемых файлов, объектного кода и динамических библиотек, используемый в 32- и 64-разрядных версиях операционной системы Microsoft Windows. Формат PE представляет собой структуру данных, содержащую всю информацию, необходимую PE-загрузчику для отображения файла в память. Исполняемый код включает в себя ссылки для связывания динамически загружаемых библиотек, таблицы экспорта и импорта API функций, данные для управления ресурсами и данные локальной памяти потока (TLS).

MZ — стандартный формат 16-битных исполняемых файлов с расширением .EXE для DOS. Назван так по сигнатуре — ASCII-символам MZ (4D 5A) в первых двух байтах. Эта сигнатура — инициалы Марка Збиковски, одного из создателей MS-DOS.

Формат был разработан как замена устаревшему формату .COM. Исполняемые файлы MZ включают метаданные, могут иметь размер больше 64 Кбайт и использовать несколько сегментов памяти различного типа (кода, данных и стека), точка входа в программу также может быть в любом месте (в файлах .COM выполнение команд всегда начинается непосредственно с начала файла). Метод загрузки исполняемого файла определяется по сигнатуре: при её наличии обрабатывается MZ-заголовок, при отсутствии файл запускается как .COM — независимо от расширения файла (например, в последних версиях MS-DOS интерпретатор командной строки COMMAND.COM на самом деле является EXE-файлом).

Исполняемые файлы более поздних форматов для Windows начинаются с MZ-заглушки. Обычно заглушка, добавляемая компиляторами, выводит сообщение наподобие «This program cannot be run in DOS mode» («Эту программу невозможно запустить в режиме DOS»).

Технические детали PE Portable Executable (PE, «переносимый исполняемый»)
- сигнатура
- структура
- таблица импорта
- таблица экспорта
- таблица перемещений

Сигнатура
Первые 2 байта PE файла содержат сигнатуру 0x4D 0x5A — «MZ» (как наследник MZ-формата). Далее двойное слово по смещению 0x3C содержит адрес PE-заголовка. Последний начинается с сигнатуры 0x50 0x45 — «PE».


Структура
Файл PE состоит из нескольких заголовков и секций, которые указывают динамическому компоновщику, как отображать файл в память. Исполняемый образ состоит из нескольких различных областей (секций), каждая из которых требует различных прав доступа к памяти; таким образом, начало каждой секции должно быть выровнено по границе страницы. Например, обычно секция
.text, которая содержит код программы, отображена как исполняемая/доступная только для чтения, а секция
.data, содержащая глобальные переменные, отображена как неисполняемая/доступная для чтения и записи.

.text: Code
.data: Initialized data
.bss: Uninitialized data
.rdata: Const/read-only (and initialized) data
.edata: Export descriptors
.idata: Import descriptors

The DATA Section
data section - используется для объявление инициализированных данных или констант
Эти данные не изменяются в процессе выполнение. Можно объявлять переменные, константы,
имена файлов, размер буфера и т.д.

The BSS Section
bss section - используется для объявления переменных.

The TEXT Section
text section - используется для хранения кода.
global_start - говорит ядру где начинает выполнятся программа

Таблица импорта
Одна из известных секций — таблица адресов импорта (IAT — Import Address Table), которая используется в качестве таблицы поиска, когда приложение вызывает функцию из другого модуля. Это может быть сделано и в форме импорта по порядковому номеру функции (ordinal), и импорта по её имени. Поскольку скомпилированной программе неизвестно расположение библиотек, от которых она зависит, то требуется производить косвенный переход всякий раз, когда происходит вызов API-функции. Когда динамический компоновщик загружает модули и объединяет их, он записывает действительные адреса в область IAT так, чтобы они указали на ячейки памяти соответствующих библиотечных функций.

Таблица экспорта
Таблица адресов экспорта (EAT — Export Address Table) нужна для того, чтобы один модуль (обычно это динамически загружаемая библиотека) мог указать другим модулям, какие функции они могут из него импортировать, и по каким адресам последние расположены.

Таблица перемещений
Файлы PE не содержат позиционно-независимого кода. Вместо этого они скомпилированы для предпочтительного базового адреса, и все адреса, генерируемые компилятором/компоновщиком, заранее фиксированы. Если PE-файл не может быть загружен по своему предпочтительному адресу (потому что он уже занят чем-то ещё), операционная система будет перебазировать его. Это включает в себя перевычисление каждого абсолютного адреса и изменение кода для того, чтобы использовать новые значения. Загрузчик делает это, сравнивая предпочтительный и фактический адреса загрузки, и вычисляя значение разности. Тогда для получения нового адреса ячейки памяти эта разность складывается с предпочтительным адресом. Базовые адреса перемещений хранятся в списке и при необходимости добавляются к существующей ячейке памяти.

Теперь используем PeiD - Один из самых популярных анализаторов исполняемых файлов.
Откроем наш файл example.exe в программе PeiD.

Откроем EP Section .text -> секция кода
 
Здесь мы видим
.text: Code
.data: Initialized data
.rdata: Const/read-only (and initialized) data
.bss: Uninitialized data
.edata: Export descriptors
.idata: Import descriptors
Откроем PE Details
 

Таблица адресов импорта (IAT — Import Address Table), которая используется в качестве таблицы поиска, когда приложение вызывает функцию из другого модуля.
Таблица адресов экспорта (EAT — Export Address Table) нужна для того, чтобы один модуль (обычно это динамически загружаемая библиотека) мог указать другим модулям, какие функции они могут из него импортировать, и по каким адресам последние расположены.
TLSTable - данные для управления ресурсами и данные локальной памяти потока (TLS).
FLS - file location calculator

Для проверки упакован файл или нет используем дополнительные функции PeiD

Теперь рассмотрим инструмент LordPe
LordPe -  Инструмент для системных программистов которые нуждаются в ручном редактирование исполняемых файлов (Portable Executable).
Здесь мы видим аналогично PeiD разделы 

Таблица адресов импорта (IAT — Import Address Table), которая используется в качестве таблицы поиска, когда приложение вызывает функцию из другого модуля.
Таблица адресов экспорта (EAT — Export Address Table) нужна для того, чтобы один модуль (обычно это динамически загружаемая библиотека) мог указать другим модулям, какие функции они могут из него импортировать, и по каким адресам последние расположены.
TLSTable - данные для управления ресурсами и данные локальной памяти потока (TLS).
FLS - file location calculator
 

Здесь мы видим байты
Сигнатура
Первые 2 байта PE файла содержат сигнатуру 0x4D 0x5A — «MZ» (как наследник MZ-формата). Далее двойное слово по смещению 0x3C содержит адрес PE-заголовка. Последний начинается с сигнатуры 0x50 0x45 — «PE».

Как сделать файл записывающимся - writable
Идем в секцию Subsystem -> .text -> открываем секцию .text и ставим галочку writable





Используем - Ollydbg -   32-битный отладчик уровня ассемблера для операционных систем Windows, предназначенный для анализа и модификации откомпилированных исполняемых файлов и библиотек, работающих в режиме пользователя (ring-3).

Используя Ollydbg отладчик мы видим наш код.
РЕГИСТРЫ EAX, EBX, ECX, EDX, ESI, EDI, EBP (32-разрядные регистры)называются регистрами
общего назначения и могут свободно участвовать в любых математических операциях или опе-
рациях обращения к памяти.

- IDA Pro Disassembler (англ. Interactive DisAssembler) — интерактивный дизассемблер, который широко используется для реверс-инжиниринга


(int argc, char **argv) - АРУМЕНТЫ КОМАНДНОЙ СТРОКИ - формальные аргументы
.text:00401369 ; =============== S U B R O U T I N E ===================
.text:00401369
.text:00401369 ; Attributes: bp-based frame
.text:00401369
.text:00401369 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401369                 public _main
.text:00401369 _main           proc near               ; CODE XREF: ___mingw_CRTStartup+F8p
.text:00401369
.text:00401369 Format          = dword ptr -20h
.text:00401369 var_1C          = dword ptr -1Ch
.text:00401369 var_4           = dword ptr -4
.text:00401369 argc            = dword ptr  8
.text:00401369 argv            = dword ptr  0Ch
.text:00401369 envp            = dword ptr  10h
.text:00401369
.text:00401369                 push    ebp
.text:0040136A                 mov     ebp, esp
.text:0040136C                 and     esp, 0FFFFFFF0h
.text:0040136F                 sub     esp, 20h
.text:00401372                 call    ___main
.text:00401377                 mov     [esp+20h+Format], offset Format ; "How many dogs you have?\n"
.text:0040137E                 call    _printf
.text:00401383                 lea     eax, [esp+20h+var_4]
.text:00401387                 mov     [esp+20h+var_1C], eax
.text:0040138B                 mov     [esp+20h+Format], offset aD ; "%d"
.text:00401392                 call    _scanf
.text:00401397                 mov     eax, [esp+20h+var_4]
.text:0040139B                 mov     [esp+20h+var_1C], eax
.text:0040139F                 mov     [esp+20h+Format], offset aSoYouHaveDDogs ; "So, you have %d dogs!\n "
.text:004013A6                 call    _printf
.text:004013AB                 call    _getchar
.text:004013B0                 call    _getchar
.text:004013B5                 mov     eax, 0
.text:004013BA                 leave
.text:004013BB                 retn
.text:004013BB _main           endp
.text:004013BB
.text:004013BB ; --------------------------------------------------


Теперь попробуем упаковать файл. Программа для упаковки файлов upx307w. Упаковывают файл в целях защиты от реверса и обеспечения безопасности кода. После упаковки мы увидим, что код станет сложно анализировать. Используя командную строку введем следующую команду.
Теперь попробуем упаковать файл. Программа для упаковки файлов upx307w.
Упаковывают файл в целях защиты от реверса и обеспечения безопасности кода.
После упаковки мы увидим, что код станет сложно анализировать.
Используя командную строку введем следующую команду

C:\Users\Lisa-Alisa>C:\Users\Lisa-Alisa\Documents\upx307w\upx.exe C:\Users\Lisa-
Alisa\Desktop\example.exe
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2010
UPX 3.07w       Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 08th 2010

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
     71233 ->     45121   63.34%    win32/pe     example.exe

Packed 1 file.


Теперь наш файл упакован.
Посмотрим теперь как изменился файл с помощью PeiDМы видим, что программа упакована UPX упаковщиком.

Здесь мы тоже видим, что наш код запакован и обфусцирован и не читаем.
 

РЕЗЮМЕ
Программа на языке С состоит из одного или большего числа функций С. Каждая программа на С должна содержать функцию с именем main ( ) , поскольку именно эта функция вызывается в момент запуска программы. Простая функция состоит из заголовка, за которым следует открывающая фигурная скобка, далее следуют операторы, образующие тело функции, за которой следует завершающая или закрывающая фигурная скобка.
Каждый оператор языка С является инструкцией компьютеру и обязательно заканчивается точкой с запятой. Оператор объявления назначает переменной имя и определяет тип данных, которые будет храниться в этой переменной. Имя переменной может служить примером идентификатора. Оператор присваивания устанавливает значение переменной или используя более общий термин, выделяет ей пространство в памяти. Вызов функции запускает на выполнение функцию, имя которой указано в
обращении. По выполнении вызванной функции программа переходит к выполнению оператора, следующего за вызовом функции.
Функция p r i n t f ( ) может использоваться для печати фраз и значений переменных. Синтаксис языка - это набор правил, определяющий способ , посредством которого допустимые операторы в этом языке группируются в единую последовательность.
Семантика оператора есть его смысловое значение. Компилятор позволяет вам обнаруживать синтаксические ошибки, однако синтаксические ошибки проявляются в программе лишь после того, как эта программа будет откомпилирована . Обнаружение семантических ошибок предусматривает мониторинг состояния программы, то есть, значений всех переменных на каждом шаге выполнения программы. И, наконец, ключевые слова образуют словарь языка С .