Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 8 мая!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь


Модификация исполняемых PE-файлов




Массу крэкерских инструментов, видеоуроков и статей вы сможете найти на видеокурсе от нашего сайта. Подробнее здесь.
  1. Intro

Наверняка многим когда-то хотелось сделать что-то с чужим кодом. Действительно, есть огромное множество великолепных ICQ-клиентов, но почему-то очень малое их количество умеет отправлять пароли пользователей на почту. И очень хочется это исправить… Разумеется, стараясь не нарушать законы «об авторском праве» - всё исключительно для эстетических целей:). Но можно приделывать не только деструктивные (для кого-то) функции, но и наоборот, к примеру… А, в общем, не буду разглагольствовать на пустом месте – вы сами придумаете, как это можно применять, а я покажу, как это можно реализовать.

PS Заранее предупреждаю – если вам кажется, что мы делаем что-то неправильно или не до конца, то не надо кричать и топать ногами – в этой статье расскажу не только про то, как нужно править PE-файлы, но и рассмотрю способы устранения некоторых нарочно сделанных реальных ошибок.

  1. Выбираем цель

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

Итак, план действий:

  1. Берём exe’шник (я буду использовать дельфийский проект с пустой формой, см. Приложение).

  2. Вставляем свой код так, чтобы он выполнялся при запуске.

В этой статье, я попробую вставить код, который запрашивает http://ya.ru/ и сохраняет результат в “a.txt”

  1. Берём скальпель.

Открываем наш файл (target.exe) в Olly Debugger:

Модификация исполняемых PE-файлов

У нас есть 2 варианта – так как места в секции кода почти всегда мало (в смысле RawSize – размер в исполняемом файле), а размер в памяти VirtualSize >> RawSize, то в конце кода у нас есть достаточно большой нулевой блок. Мы можем поступить одним из двух способов – записать свой код поверх этих нулей, потом сделать дамп из памяти и получить то, что хотим, а можем заранее создать свою секцию и писать в неё. Что касается имеющейся секции данных, то там, как правило, место всегда есть, но если создавать свою секцию кода, то свою секцию данных создать – уже не проблема. А можно сделать её одновременно и секцией данных, разрешив писать в неё… Ну, в общем, всё по порядку.

  1. Подготовка к операции

Сейчас я пойду по второму пути (в первый раз, когда я делал такое, я шёл по первому, и… в общем, это было очень муторно. А если вы захотите всё-таки когда-то делать так (например, кажется, что код влезет в RawSize, а он не влезает…), то вот вам мой совет: единственная сработавшая у меня связка – это OllyDump без восстановления импорта + ImpRec). Поэтому закрываем Олю и открываем наш файл в LordPE или PETools:

Модификация исполняемых PE-файлов

И идём в раздел “Sections”:

Модификация исполняемых PE-файлов

Нажимаем правую кнопку на какой-нибудь секции, выбираем “add section header”:

Модификация исполняемых PE-файлов

В конце списка появляется новая секция. Щёлкакем на ней правой кнопкой, выбираем “edit section header”:

Модификация исполняемых PE-файлов

  1. В поле Name вводим какое-нибудь название секции, например “.code”

;

  1. Поля VirtualAddress и RawOffset не трогаем – это адреса секции в памяти и в файле соответственно, вычисляются как

VirtualAddress = ((VirtualAddress(предыдущая секция) + VirtualSize(предыдущая секция) – 1) div VirtualAlign) + 1) * VirtualAlign;

(Перевожу на русский – наименьшее число, делящееся на VirtualAlign и большее последнего адреса предыдущей секции:))


Аналогично считается и RawOffset, только вместо VirtualAlign стоит FileAlign.

Их LordPE считает автоматом, и менять их не надо! Кстати, VirtualAlign и FileAlign – тоже поля заголовка PE, должны быть степенями двойки, притом VirtualAlign >= 1000h; FileAlign >= 200h. Подробнее это рассмотрено в [1].

  1. VirtualSize и RawSize.

А вот это нам и надо! RawSize – размер секции в файле, а VirtualSize – в памяти. Поставим RawSize = 1000 (ну уж 4кб нам под код хватит:)), а VirtualSize = 4000 (то есть 16кб). «Зачем нам такой большой VirtualSize?»,- спросите вы,- «Ведь если код в файле занимает 4кб, то зачем под него выделять целых 16?» Просто я хочу писать сюда не только код, но и данные, чтобы не создавать новую секцию, хоть это и не трудно. А помните, что мы хотели сделать? Да-да, загрузить http://ya.ru/ . А сколько он там весит? Не помню, но в 16кб, думаю, влезет…

  1. А теперь редактируем флаги секции. Нажимаем на кнопочку рядом с полем Flags:

    Модификация исполняемых PE-файлов

То, что нам нужно, уже отмечено – проверяем:

  1. Что-то в секции можно выполнять

  2. Из неё можно читать

  3. В неё можно писать

  4. В ней есть код

  5. В ней есть инициализированные данные

  6. В ней есть неинициализированные данные

А если что-то здесь лишнее, то это не смертельно.

Всё, жмём «ОК», потом, запомнив VirtualOffset и RawOffset нашей секции (60000h и 59E00h), закрываем окошко с секциями. Зачем запоминать VirtualOffset? Всё дело в том, что есть в PE-заголовке такое поле, как BaseOfCode. В нём сейчас записан VirtualOffset (всё, надоело, дальше вместо VirtualOffset буду говорить просто RVA) секции «CODE», и Olly, которым мы будем пользоваться дальше, не будет анализировать (потом об этом) нашу секцию, считая её чем-то странным и не понимая, как туда попала программа. А ориентируется он как раз на BaseOfCode. Значит, пишем в BaseOfCode запомненный RVA. А RawOffset… В общем, скоро поймёте. Теперь смотрим на важный параметр EntryPoint (Если не ясно, что это, то вам в [1]), запоминаем его значение (4CA98), и пишем туда (RVA нашей секции + 5). Почему +5, станет ясно потом. Теперь заголовок выглядит как-то вот так:

Модификация исполняемых PE-файлов

Всё, жмём Save, жмём “OK”, и пытаемся запустить файл. А он не запускается… И правильно! Секцию-то мы объявили, а записать – не записали! Открываем target.exe во FlexHex и идём в самый конец файла. Теперь ищем то место, где будет новая секция. А она начинается с запомненного нами RawOffset (назовём его Raw = 59E00). Если последний существующий байт файла имеет адрес, отличный от (Raw-1), то забиваем нулями всё место от конца файла до этого числа (Щёлкаем после последнего байта в файле, далее Edit->Insert Zero Block; Block Size = Raw - адрес последнего байта - 1. Калькулятор вам в помощь :)). Но нам этого делать не надо – у нас и так всё хорошо.

Теперь щёлкаем на пустой квадратик по адресу Raw, далее Edit->Insert Zero Block; Block Size = размер нашей секции, RawSize, то есть 1000h.

Модификация исполняемых PE-файлов

“ОК”, “Ctrl-S”, “Exit” :)

Всё, секция готова, пытаемся запустить файл… Ошибка…

Модификация исполняемых PE-файлов

Но уже «хорошая»! То есть наша программа запускается! Ура-ура! Это валидный PE-файл!

  1. Операция

Снова открываем наш файл в Оле.

Модификация исполняемых PE-файлов

Поднимаемся наверх (до конца – на две строчки :)) Жмём пробел, находясь на самой первой строчке, и пишем «jmp 44CA98». Узнаёте? Да-да, это та самая исходная EntryPoint, вернее (EntryPoint + ImageBase) (далее OEP), где ImageBase тоже можно посмотреть в PE-заголовке, но вообще-то он всегда равен 400000h :). Вот этот далёкий прыжок и съел первые 5 байт секции. Можно это сделать и в конце, конечно, но легче сразу записать сюда прыжок на OEP, а потом уже не задумываться и после выполнения кода прыгать в начало секции, а не где-то записанное число… Проверим – работает ли программа? Для этого из EP – то место, где сейчас остановлена программа, прыгаем на OEP, то есть в начало секции: (чтобы попасть на место, где сейчас остановлена программа, можно нажать правую кнопку -> Go to -> Origin или просто “*” на NumPad’е. И вообще, она выделена синим цветом. Ладно, не буду больше ничего рассказывать про Олю, ибо и так много всего написано. Хотя бы справка :)). Пишем в EP: “jmp 460000”. Повторяю: щёлкаем на строчке, нажимаем пробел, пишем команду, нажимаем “Enter”.

Модификация исполняемых PE-файлов

Запускаем программу (F9). Она работает!!! Закрываем форму, а в Оле – “Ctrl+F2”: перезагружаем (нет, не компьютер:)) программу. А! Наш прыжок на OEP пропал! Ну ладно, восстановим его (либо вводим заново, либо, так как Оля сохраняет изменения в файле, то открываем Patches:

Модификация исполняемых PE-файлов

выделяем первый и единственный пункт и нажимаем пробел – всё вернулось :)).

А теперь начинаем кодить! Пустой прыжок сразу на OEP, сделанный для проверки, нам уже не нужен, поэтому начинаем писать поверх него. Пытаемся создать файл с помощью CreateFileA: параметры мы, разумеется, не помним, поэтому пишем несколько раз “push 0”, а потом “call CreateFileA". А теперь то, ради чего мы меняли BaseOfCode: жмём “Ctrl-A”, и Оля анализирует наш код. Если бы мы BaseOfCode не трогали, то и Оля бы отказалась анализировать нашу секцию.

Модификация исполняемых PE-файлов

Вот справа указаны все параметры. Нам нужны только mode, access и filename, остальное для примера не важно. Идём куда-нибудь вниз, например на 461000, и, нажав (Ctrl+E), записываем туда “a.txt” и 0-символ, означающий конец строки:

Модификация исполняемых PE-файлов

«ОК»… Ой, как некрасиво… Какие-то жуткие команды… Выделяем наш “a.txt”, нажимаем правую кнопку->Analysis->During next analysis…->ASCII text; Ctrl+A. Вот, так лучше:

Модификация исполняемых PE-файлов

Запоминаем адрес 461000, и идём наверх, и записываем поверх того что там есть (и, когда не жалко, нажимаем ctrl+A):

Модификация исполняемых PE-файлов

Кстати, можно писать выражения типа “push CREATE_ALWAYS” и “push GENERIC_WRITE” – Оля их понимает. Далее по F8 доходим до 46001E. В EAX – число, не равное FFFFFFFF, то есть функция успешно выполнена. В EAX – handle открытого файла. Всё, закрываем его (CloseHandle) -пока на этом остановимся – и прыгаем на OEP:

Модификация исполняемых PE-файлов

Трассируем по F8 до прыжка: eax = 1. Всё работает. А сейчас, давайте сохраним изменения в exe’шнике. Выделяем всё изменённое (это делается так же, как и в любом текстовом редакторе – с помощью Shift и стрелок или мышки), не забывая про 461000 с “a.txt”. А точно! Мы же не влезем в размер секции в файле! Слишком далеко мы поставили “a.txt”! Ладно, перенесём его на чуть пораньше: на 460600, а там удалим (или аналогично через “Patches”, или выделяем, правая кнопка -> Binary -> Fill with 00’s) и поправим код (выделяем команду push 461000 -> пробел -> push 460600).

Модификация исполняемых PE-файлов

Снова выделяем всё изменённое. Далее: либо [правая кнопка -> Copy to executable -> Selection], либо [правая кнопка -> binary -> copy; правая кнопка -> view -> executable file; откроется окошко с выделенным текстом; в нём: правая кнопка -> binary -> paste]. Тем самым мы заменили оригинальные байты в файле на то, что мы написали. Закрываем окошко, Оля нам предлагает сохраниться – сохраняемся, например в target_.exe. Так, у нас в папке уже есть какой-то a.txt. Удаляем его и запускаем программу. Вау! Она запускается, работает, и… даже файл создаётся! Казалось бы всё, основная идея ясна, дальше всё просто… Но, увы, нет. Попробуйте запустить файл на другом компьютере – и у вас, скорее всего, ничего не получится. Всё дело в том, что, если вы теперь нажмёте пробел на «call функция из библиотеки», то вы увидите что-то типа “CALL 7C801A24”, то есть абсолютный адрес в библиотеке. А если у нас другая версия kernel32.dll, к примеру? Тогда произойдёт ошибка, и программа работать не будет. Поэтому нам надо грамотно импортировать все используемые нами функции. Для этого существует мехонизм под названием Import Address Table (IAT). Как она работает, я подробно рассказывать не буду, а ограничусь лишь тем, что скажу, что, используя данный механизм, программа (вернее, не совсем программа, ну да ладно) при загрузке в память вычисляет адреса импортируемых функций по их символьным именам. Итак, нам надо описать должным образом нужные нам функции. Конечно, некоторые из них уже описаны, но легче описать их заново, чем искать в других секциях… А если программа ещё и запакована, что, кстати, в случае отсутствия проверки CRC никоим образом не отражается на нашей работе, то там эта оригинальная IAT ещё и спрятана.

Для нашей цели необходимы следующие функции: CreateFileA, WriteFile, CloseHandle из библиотеки kernel32.dll и WSAStartup, connect, send, recv и WSACleanup из WS2_32.dll. Поэтому закрываем Олю и открываем нашу программу в LordPE (PETools тоже умеет редактировать IAT, но у неё с этим иногда, почему-то, возникают недоразумения в виде обрезания имён функций – так WSAStartup может стать WSAStartu и т.п.):

Модификация исполняемых PE-файлов

Directories -> ImportTable -> … -> правая кнопка -> add import…

В появившемся окне добавляем вначале функции из kernel32.dll (вводим название библиотеки, а потом по очереди добавляем нужные функции кнопкой «+»):

Модификация исполняемых PE-файлов

Закрываем диалог, а теперь вызываем его ещё раз, чтобы добавить функции WinSock’а:

Модификация исполняемых PE-файлов

Закрываем диалог, закрываем LordPE, стараясь нажимать Save везде, где можно. Попробуем запустить программу… Она работает. А если бы мы что-нибудь напутали, то появилась бы ошибка вида: «Точка входа в функцию xxx не найдена в библиотеке yyy».

Запускаем программу в Olly, после этого снова загружаем её в LordPE и идём в ту же самую таблицу импорта. «Зачем мы его закрывали?»,- спросите вы. А затем, чтобы он дал нам возможность работать с файлом. Теперь в заголовке лорда видим слова “Read only”, то есть теперь мы можем только смотреть на заголовок, но не можем его модифицировать. Смотрим на добавленные нами импорты:

Модификация исполняемых PE-файлов

Нам нужен ThunkRVA – по этому адресу будет находиться адрес функции в памяти после загрузки программы (разумеется, +ImageBase). И в данном свете вместо “call CreateFileA" надо писать “call xxxxxxxx”, где по адресу xxxxxxxx находится команда “jmp dword ptr [464035]”, или просто “jmp [464035]”, так как 464035 = ImageBase + ThunkRVA фунуции CreateFileA. Да, действительно, это правда – надо делать call на jmp – это не ошибка и не бред, а на самом деле очень логичная операция, так как, во-первых, к одной функции программа может стучаться несколько раз, а, во-вторых, хочется, чтобы к функциям обращение шло через обычный call. Итак, нам надо записать эти самые прыжки. Запишем их начиная с адреса 460500 (они должны попадать внутрь файла, то есть до 461000). Переключаемся в Олю, переходим на этот адрес (быстрый переход – Ctrl+G), нажимаем пробел и пишем по очереди jmp [464035], jmp [464039], jmp [46403D] – импорт из kernel32.dll, и также с WS2_32.dll – jmp [64082], jmp [64086] и т.д. Кстати, компиляторы часто зачем-то разделяют эти прыжки командой “mov eax, eax”, но мы этим заниматься не будем.

Модификация исполняемых PE-файлов

Теперь идём в начало секции, и изменяем “call CreateFileA” на “call 460500”, аналогично – CloseHandle. (Для этого выделяем команду, жмём пробел и пишем новый код):

Модификация исполняемых PE-файлов

Заметим, что Olly заменил наши call’ы на логичные названия. Если нажать Ctrl+A, то он точно так же выводит список параметров функции. Можно убедиться, что всё действительно работает, можно сохранить уже имеющиеся изменения уже описанным способом, но я не буду этим заниматься, а постараюсь быстренько доделать всё до победного конца.

  1. Заканчиваем план

Удалять открытие файла мне лень, поэтому пусть структура кода будет такой:

  1. Открываем файл

  2. Инициализируем WinSock

  3. Подключаемся к Ya.ru (213.180.204.8)

  4. Отправляем GET-запрос

“GET / HTTP/1.1”, CR, LF, “Host: ya.ru”, CR, LF, CR, LF.

  1. Получаем данные

  2. Сохраняем в файл

  3. Закрываем WinSock

  4. Закрываем файл

Итак, поехали!

  1. Файл уже открыт. Надо либо удалить код с CloseHandle (выделяем -> пр. кнопка -> Binary -> Fil with 00’s), либо писать поверх – закрытый файл нам не нужен.

  2. WSAStartup – это у нас «CALL 00460512»

Параметры можно посмотреть вышеописанным способом, а можно вспомнить:)

Модификация исполняемых PE-файлов

Нам нужно найти место, где мы будем хранить WSAData – то, что вернёт WSAStartup (а версию сокетов я поставил 2, т.е. 2.0). WSAData’у можно хранить в виртуальной памяти, не трогая место в файле. Поэтому смело указываем что-нибудь типа 461000 – это адрес внутри нашей секции, в которую мы можем писать данные, но он уже вне секции в файле, иначе говоря, этот адрес находится от начала секции на расстоянии, большем, чем её RawSize. Хотя нам сама структура WSAData как результат WSAStartup и не понадобится, но, если что, то она – там.

Модификация исполняемых PE-файлов

Можем проверить – трассируем программу (по F8) – и видим, что по адресу 461000 действительно что-то появилось. Кстати, если где-то в вашем коде – ошибка, а вы уже прошли то место, где она возникла, то всегда можно изменить текущую выполняемую инструкцию – выбираем интересующее нас место и нажимаем Ctrl+”*” c NumPad'а (или прав. кнопка -> New Origin Here).

  1. Подключаемся к ya.ru.

Для этого нам нужно где-то хранить его IP-адрес, и хранить его мы должны, так сказать, в физическом месте файла, то есть он должен «влезть» в RawSize. Запишем его рядом с “a.txt” (в 460606):

Модификация исполняемых PE-файлов

А заодно нажмём Ctrl+A :)

И в этот прекрасный момент мы понимаем, что забыли подгрузить функции inet_addr, socket и closesocket :) Ну, ничего, это поправимо! Сохраняем все уже сделанные в Оле изменения (конечно, только то, что нам нужно сохранить – нам не нужна полученная WSAData, да и места под неё в файле нет!) в файле target_2.exe вышеописанным способом, закрываем Олю, закрываем LordPE и открываем его снова с target_2.exe, на этот раз – с правом на запись. Заходим в таблицу импорта, добавляем ещё одну группу импортов из WS2_32.dll (да, ничего плохого в этом нет) с нужными функциями.

Модификация исполняемых PE-файлов

Модификация исполняемых PE-файлов

Наши ThunkRVA – это 640C8, 640CC, 640D0. Закрываем лорда, он нам больше не понадобится, и открываем target_2.exe в Оле. Идём в то место, где мы писали прыжки на внешние функции, и дописываем туда jmp [4640C8] и т.п.

Модификация исполняемых PE-файлов

Для подключения нам нужно заполнить структуру SockAddr (её описание можно без труда найти, я заполню её без лишних комментариев). Хранить её мы будем, к примеру, по адресу 461020. Она занимает 16 байт.

Запишем туда адрес сервера (он будет в 461020+4). Идём в начало кода, и вызываем оттуда inet_addr с параметром – адресом строки с IP.

Модификация исполняемых PE-файлов

Полученное в eax значение сохраняем в 461024:

MOV DWORD PTR DS:[461024], EAX

Первые 2 байта структуры занимает WORD 2:

MOV WORD PTR DS:[ 461020], 2

Далее 2 байта – это htons(80)=5000h, то есть порт.

MOV WORD PTR DS:[ 461022], 5000

Итак, структуру заполнили, осталось открыть сокет функцией socket(AF_INET, SOCK_STREAM, IPPROTO_IP):

PUSH 0 // это - IPPROTO_IP

PUSH 1 // SOCK_STREAM

PUSH 2 // AF_INET

CALL 460536 //socket

Сохраним полученный в EAX сокет в 461040:

MOV DWORD PTR DS:[461040], EAX

Осталось подключиться с помощью connect’а:

PUSH 10 // те самые 16 байт – размер структуры

PUSH 461020 // адрес структуры

PUSH DWORD PTR DS:[461040] // тут лежит наш дескриптор сокета

CALL 460518 //connect

Мы подключились!


Модификация исполняемых PE-файлов

  1. Дальше для функции send нам нужно куда-то записать сам GET-запрос. И его рядом с «a.txt» поставим :)

Модификация исполняемых PE-файлов

ОК, Ctrl+A. Считаем размер передаваемых данных (нужен для send): 31d=1Fh. Запоминаем адрес: 460614, и возвращаемся к коду. Пишем:

PUSH 0 //какие-то флаги…

PUSH 1F //размер отправляемых данных

PUSH 460614 //адрес отправляемых данных

PUSH DWORD PTR DS:[461040] //дескриптор сокета

CALL 0046051E //send

  1. Теперь получаем ответ – выделим под него 4кб в зарезервированной памяти, начиная с адреса, ну, к примеру, 462000.

PUSH 0 // опять какие-то флаги…

PUSH 1000 //выделяем под буфер для загружаемых данных 4кб

PUSH 462000 //адрес буфера

PUSH DWORD PTR DS:[461040] //дескриптор сокета

CALL 00460524 //recv

Весь код:

Модификация исполняемых PE-файлов

Трассируем программу до нулей.

Если всё прошло без ошибок (а оно должно пройти без ошибок), то тогда, начиная с адреса 462000 должно быть содержание сайта ya.ru. Проверим – да, действительно, там появилось что-то похожее. В eax после выполнения recv лежит размер полученных данных – хорошо бы его где-то запомнить, чтобы потом WriteFile знал, сколько байт писать. А сейчас мы как раз должны его вызвать. Но… нам нужен дескриптор файла, открытого в CreateFileA, а мы его не сохранили… Что же делать? Опять есть 2 варианта (ой, как всё ветвится-то!). Первый – «занопить» тот вызов CreateFileA’а, то есть забить командами nop (выделяем -> пр. кнопка -> Binary -> Fill with NOP’s) и вызвать её уже после всяких операций с сокетами. А я воспользуюсь другим: в коде на месте

CALL <JMP.&kernel32.CreateFileA>

поставим прыжок куда-нибудь подальше (заменяя его, лучше поставить галочку “Fill with NOP’s”), а там, в этом самом «по-дальше», выполним этот самый call, сохраним результат куда-нибудь и вернёмся обратно. Иначе говоря, схема вот такая:




Модификация исполняемых PE-файлов

Невольно напрашивается аналогия с вызовом функции.

Возьмём в качестве xxxxxx, к примеру, 460200 – с запасом:

Модификация исполняемых PE-файлов

Теперь в 460300 будет лежать дескриптор файла. А наверху:

Модификация исполняемых PE-файлов

Дописываем нашу программу – нам осталось только закрыть сокет, закрыть WinSock, сохранить в файл и закрыть его. Но, для начала, так как мы поменяли что-то в уже пройденных командах, лучше перезапустить программу (Ctrl + F2), чтобы пройти их заново. Но перед этим надо убедиться, что в Олиных настройках разрешено сохранение информации об исследуемых файлах, то есть она сохраняет сделанные патчи (Alt-O -> Security -> Save user data outside any module to main .udd file, вроде, должен быть включён, а, может, Olly всегда сохраняет эти данные – честно говорю, не помню:)). Тогда и после перезапуска программы, и даже после перезапуска самого отладчика, при открытии диалога (или как там это окошко назвать?) Patches (как это делается, я уже показал), отобразится куча всяких изменений. Пробелом восстанавливаем те из них, которые находятся, вернее, должны будут находиться, внутри исполняемого файла, то есть:

Модификация исполняемых PE-файлов

После этого с чистой совестью доходим до конца написанного нами кода по F8 или поставив бряк на последней команде (F2) и пустив программу работать саму (F9). Что там дальше? Дописываем наш код:

Сохраняем результат recv’а, то есть размер полученных данных, к примеру, в [463000]:

MOV [463000], EAX

Закрываем сокет:

Push [461040]

CALL 0046053C

А дальше всё понятно, подробно объяснять не буду:

Вызываем WSACleanup, вызываем WriteFile, вызываем CloseHandle:


Модификация исполняемых PE-файлов


Ну, как бы, вроде, и всё… Но что-то мы забыли… Что же? Правильно, прыжок на OEP:

Модификация исполняемых PE-файлов

Ну вот, a теперь точно всё. Выделяем весь код от начала секции до 460999 включительно (ну, или до последнего использованного адреса), и сохраняем их в файл, например, “fin.exe” (это я тоже уже описал). Можем пустить дальше программу в Оле по F9 или F8, чтобы убедиться в отсутствии ошибок, а можем закрыть уже успевший надоеть нам отладчик и запустить fin.exe. Так и сделаем – закрываем Олю, удаляем старый файл “a.txt”,чтобы не мешал, и запускаем fin.exe. Ждём – всё-таки загрузка страницы не мгновенна… Ура! Всё работает :).

  1. Заключение

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

Что планируется в будущем? В будущем я постараюсь описать процесс внедрения не только в начало программы, то есть, по сути, некоторую «склейку», но и в некоторые её функции, а также, если будет не лень, то и внедрение в GUI.

Greets to antichat.ru, cracklab.ru и redxak.net, который обязательно когда-нибудь появится, а также спасибо inf’у, за хороший ICQ-клиент и вдохновение:)

Персональные приветы следующим людям, имеющим прямое отношение к реверсингу: XSerg, ProTeuS и 0x0c0de, а также Sealed, Apocalipse, Terrific, Jan3A1r (повторяю - нелепый ник!), и т.д.

  1. Полезные ссылки

  1. http://www.insidepro.com/kk/019/019r.shtml - Хорошая статья про PE

  2. http://tuts4you.com/ – тут можно скачать все использованные в статье программы

  3. http://redxak.net/

  4. http://antichat.ru/

  5. http://cracklab.ru/

  6. http://wasm.ru/

  7. http://ollydbg.de/

  1. Приложения

  1. Исходный target.exe

  2. Получившийся fin.exe

  3. Получившийся a.txt

(с) 73ru5 aka desTiny, 2008.



Скачать статью "Модификация исполняемых PE-файлов" в авторском оформление + файлы.
пароль архива на картинке



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS