ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи > Авторские статьи
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

Модификация исполняемых Pe-файлов
  #1  
Старый 22.03.2008, 12:44
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию Модификация исполняемых Pe-файлов

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

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


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


II. Выбираем цель
Прежде, чем что-то делать, надо понять, что именно мы хотим сделать. В данном случае, у нас есть неимоверное количество потенциальных вариантов, но сейчас я покажу только, на мой взгляд, самый простой случай.
Итак, план действий:
1) Берём exe’шник (я буду использовать дельфийский проект с пустой формой, см. Приложения).
2) Вставляем свой код так, чтобы он выполнялся при запуске.
В этой статье, я попробую вставить код, который запрашивает http://ya.ru и сохраняет результат в “a.txt”.
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #2  
Старый 22.03.2008, 12:44
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

III. Берём скальпель.
Открываем наш файл (target.exe) в Olly Debugger:

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


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


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


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


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


1) В поле Name вводим какое-нибудь название секции, например “.code”;
2) Поля VirtualAddress и RawOffset не трогаем – это адреса секции в памяти и в файле соответственно, вычисляются как
VirtualAddress = ((VirtualAddress(предыдущая секция) + VirtualSize(предыдущая секция) – 1) div VirtualAlign) + 1) * VirtualAlign;
(Перевожу на русский – наименьшее число, делящееся на VirtualAlign и большее последнего адреса предыдущей секции =) )

Аналогично считается и RawOffset, только вместо VirtualAlign стоит FileAlign.
Их LordPE считает автоматом, и менять их не надо! Кстати, VirtualAlign и FileAlign – тоже поля заголовка PE, должны быть степенями двойки, притом VirtualAlign >= 1000h; FileAlign >= 200h. Подробнее это рассмотрено в [1].
3) VirtualSize и RawSize.
А вот это нам и надо! RawSize – размер секции в файле, а VirtualSize – в памяти. Поставим RawSize = 1000 (ну уж 4кб нам под код хватит), а VirtualSize = 4000 (то есть 16кб). «Зачем нам такой большой VirtualSize?»,- спросите вы,- «Ведь если код в файле занимает 4кб, то зачем под него выделять целых 16?» Просто я хочу писать сюда не только код, но и данные, чтобы не создавать новую секцию, хоть это и не трудно. А помните, что мы хотели сделать? Да-да, загрузить http://ya.ru. А сколько он там весит? Не помню, но в 16кб, думаю, влезет…
4) А теперь редактируем флаги секции. Нажимаем на кнопочку рядом с полем Flags:


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

a) Что-то в секции можно выполнять
b) Из неё можно читать
c) В неё можно писать
d) В ней есть код
e) В ней есть инициализированные данные
f) В ней есть неинициализированные данные

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


Всё, жмём 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.


“ОК”, “Ctrl-S”, “Exit” =)
Всё, секция готова, пытаемся запустить файл… Ошибка…

Но уже «хорошая»! То есть наша программа запускается! Ура-ура! Это валидный PE-файл!
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #3  
Старый 22.03.2008, 12:45
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

V. Операция
Снова открываем наш файл в Оле.

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


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


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


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


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


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


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


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


Снова выделяем всё изменённое. Далее: либо [правая кнопка -> Copy to executable -> Selection], либо [правая кнопка -> binary -> copy; правая кнопка -> view -> executable file; откроется окошко с выделенным текстом; в нём: правая кнопка -> binary -> paste]. Тем самым мы заменили оригинальные байты в файле на то, что мы написали. Закрываем окошко, Оля нам предлагает сохраниться – сохраняемся, например в target_.exe. Так, у нас в папке уже есть какой-то a.txt. Удаляем его и запускаем программу. Вау! Она запускается, работает, и… даже файл создаётся!
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #4  
Старый 22.03.2008, 12:45
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

Казалось бы всё, основная идея ясна, дальше всё просто… Но, увы, нет. Попробуйте запустить файл на другом компьютере – и у вас, скорее всего, ничего не получится. Всё дело в том, что, если вы теперь нажмёте пробел на «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 и т.п.):


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


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


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


Нам нужен 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"


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


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

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #5  
Старый 22.03.2008, 12:46
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

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

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.
5) Получаем данные
6) Сохраняем в файл
7) Закрываем WinSock
8) Закрываем файл

Итак, поехали!
1) Файл уже открыт. Надо либо удалить код с CloseHandle (выделяем -> пр. кнопка -> Binary -> Fill with 00’s), либо писать поверх – закрытый файл нам не нужен.
2) WSAStartup – это у нас «CALL 00460512»
Параметры можно посмотреть вышеописанным способом, а можно вспомнить =)

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


Можем проверить – трассируем программу (по F8) – и видим, что по адресу 461000 действительно что-то появилось. Кстати, если где-то в вашем коде – ошибка, а вы уже прошли то место, где она возникла, то всегда можно изменить текущую выполняемую инструкцию – выбираем интересующее нас место и нажимаем Ctrl+”*” c NumPad'а (или прав. кнопка -> New Origin Here).
3) Подключаемся к ya.ru.
Для этого нам нужно где-то хранить его IP-адрес, и хранить его мы должны, так сказать, в физическом месте файла, то есть он должен «влезть» в RawSize. Запишем его рядом с “a.txt” (в 460606):


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



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


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


Полученное в 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
Мы подключились!
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #6  
Старый 22.03.2008, 12:46
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

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

ОК, Ctrl+A. Считаем размер передаваемых данных (нужен для send): 31d=1Fh. Запоминаем адрес: 460614, и возвращаемся к коду. Пишем:
Код:
PUSH 0 //какие-то флаги…
PUSH 1F //размер отправляемых данных
PUSH 460614 //адрес отправляемых данных
PUSH    DWORD PTR DS:[461040] //дескриптор сокета
CALL    0046051E //send
5) Теперь получаем ответ – выделим под него 4кб в зарезервированной памяти, начиная с адреса, ну, к примеру, 462000.
Код:
PUSH 0 // опять какие-то флаги…
PUSH 1000 //выделяем под буфер для загружаемых данных 4кб
PUSH 462000 //адрес буфера
PUSH    DWORD PTR DS:[461040] //дескриптор сокета
CALL    00460524 //recv
Весь код:

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


Невольно напрашивается аналогия с вызовом функции.
Возьмём в качестве xxxxxx, к примеру, 460200 – с запасом:


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


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


После этого с чистой совестью доходим до конца написанного нами кода по F8 или поставив бряк на последней команде (F2) и пустив программу работать саму (F9). Что там дальше? Дописываем наш код:
cохраняем результат recv’а, то есть размер полученных данных, к примеру, в [463000]:
MOV [463000], EAX
Закрываем сокет:
Push [461040]
CALL 0046053C
А дальше всё понятно, подробно объяснять не буду:
Вызываем WSACleanup, вызываем WriteFile, вызываем CloseHandle:


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

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

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #7  
Старый 22.03.2008, 12:47
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

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

Greetz to antichat.ru, cracklab.ru и redxak.net, который обязательно когда-нибудь появится, а также спасибо inf’у, за хороший ICQ-клиент и вдохновение
Персональные приветы следующим людям, имеющим прямое отношение к реверсингу: XSerg, ProTeuS и 0x0c0de, а также Sealed, Apocalipse, Terrific, Jan3A1r (повторяю - нелепый ник!), и т.д.
VIII. Полезные ссылки
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
IX. Приложения
1. Исходный target.exe - http://webfile.ru/1819431
2. Получившийся fin.exe - http://webfile.ru/1819434
3. Получившийся a.txt - http://webfile.ru/1819436

(с) 73ru5 aka desTiny, 2008.

Да, кстати, публикуется исключительно для ознакомительных целей, я не несу никакой ответственности за использование приведённых материалов.
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ

Последний раз редактировалось desTiny; 22.03.2008 в 13:13..
 
Ответить с цитированием

  #8  
Старый 25.03.2008, 00:55
ProTeuS
HARDstasy
Регистрация: 26.11.2004
Сообщений: 1,367
Провел на форуме:
4226592

Репутация: 2175


Отправить сообщение для ProTeuS с помощью ICQ
По умолчанию

хорошо статейку оформил, многим будет полезно. только вот парева небыло бы совершенно, если добавить в секцию заранее написаный базонезависимый код. и никакого импорта, никакого-инлайн асма и гемороя...
 
Ответить с цитированием

  #9  
Старый 25.03.2008, 10:37
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию

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

Конечно, можно было бы заметить, что функции можно искать и без внесения импорта, как подробно описано тут(Greetz to TermoSINteZ).

Вот небольшой экстракт кода оттуда:
Цитата:
Код:
_ReadSEH:
xor  edx, edx			
mov  eax, dword ptr fs:[edx]	;читаем элемент SEH 
dec  edx				;edx = -1
_SearchK32:
cmp  dword ptr [eax], edx	;встретили нужный ?
je _CheckK32
mov  eax, dword ptr [eax]	;получаем следующее значение 
jmp _SearchK32
        _CheckK32:
mov  eax,[eax+4]		;получаем адрес ГДЕ-ТО в kernel32.dll
xor ax,ax			;выравниваем полученный адрес
Код:
_SearchMZ:
cmp word ptr [eax],5A4Dh	;сверяем сигнатуру
je _CheckMZ
sub eax,10000h			;если неравно то ищем дальше 
jmp _SearchMZ

_CheckMZ:
mov edx, dword ptr [eax+3ch]	;переходим на PE заголовок
cmp word ptr [eax+edx],4550h	;сверяем сигнатуру
jne _Exit
Код:
_SearchAPI: 
mov esi, dword ptr [eax+edx+78h]	;RVA таблицы экспорта            
add esi,eax                   			;нормализуем адрес
add esi,18h		;получаем нужный указатель на число ;указателей на имена
xchg eax,ebx
lodsd                        			;получаем число указателей на имена
push eax
lodsd                        			;получаем адрес таблицы экспорта.
push eax
lodsd                          		;получаем указатель на та таблицу ;указателей на имена 
push eax 
add eax,ebx
push eax                     		 	;Index элемента таблицы имен
lodsd                          			;получим  указатель на таблицу ординалов
push eax
mov edi, dword ptr [esp+4*5]		;указываем на стек 
lea edi, dword ptr [edi+HeshTable] 	;получаем смещение таблицы HeshTable
mov ebp,esp				;настраиваем стек
Код:
_BeginSearch:
mov ecx, dword ptr [ebp+4*4]		;число имен функций              
xor edx,edx

_SearchAPIName:          
mov esi, dword ptr [ebp+4*1]              ;Index элемента таблицы имен                                             
mov esi, dword ptr [esi]		;таблица экспорта
add esi,ebx				;адрес  ASСII имени первой API-функции
Код:
_GetHash:
xor  eax,eax			 
push eax


_CalcHash:
ror  eax,7			;сдвигаем 
xor dword ptr [esp],eax		;ксорим
lodsb				;загружаем следующую букву
test al,al				;сверяем, конец ли имени ?
jnz _CalcHash
pop eax

_OkHash:
cmp eax, dword ptr [edi]		;сверяем полученный hash с тем что в ;таблице HeshTable
je _OkAPI
add dword ptr [ebp+4*1],4    		;сдвигаемся к другому элементу таблицы ;экспорта
inc edx
loop _SearchAPIName 
jmp _Exit                            

_OkAPI:
shl edx,1				;номер функции
mov ecx, dword ptr [ebp]               	;берем указатель на таблицу ординалов
add ecx,ebx				
add ecx,edx
mov ecx, dword ptr [ecx]
and ecx,0FFFFh
mov edx, dword ptr [ebp+4*3]             ;извлекаем Address Table RVA
add edx,ebx
shl ecx,2
add edx,ecx
mov edx, dword ptr [edx]
add edx,ebx
push edx					;сохраняем адрес найденной функции
cmp word ptr [edi+4],0FFFFh   	;последняя ?
je _Call_API
add edi,4				;следующее hash-значение функции

_NextName:          
mov ecx, dword ptr [ebp+4*2]          ;восстанавливаем начало таблицы  экспорта  
add ecx,ebx						
mov dword ptr [ebp+4*1], ecx          ;Index  в таблице имен 
jmp short _BeginSearch      

_Call_API:
Код:
….
ExitProcess    		equ [ebp-4*12]
GetProcAddress 	equ [ebp-4*13]
LoadLibrary    	equ [ebp-4*14]
SetCurrentDirectory 	equ [ebp-4*15]
EIP			equ [ebp-4*16]
Find_H		equ [ebp-4*17]
FileHandle	   	equ [ebp-4*18]
FileSize	   	equ [ebp-4*19]
….
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием

  #10  
Старый 25.03.2008, 12:02
ProTeuS
HARDstasy
Регистрация: 26.11.2004
Сообщений: 1,367
Провел на форуме:
4226592

Репутация: 2175


Отправить сообщение для ProTeuS с помощью ICQ
По умолчанию

при4ем здесь склейка, ты забиваешь руками свой скомпиленый код в заранее подготовленную секцию, априоре он никогда не спалится аверем, это просто код, разница только 4то не зависящий от базы, 4то ты и как туда будешь пихать - это второй вопрос. никто не говорит о малварях, а только об удобстве ру4ной модификации бинаря, авери будут алармать и на базонезависымый код в рантайме и на стати4ески скомпиленый с импортом и им пофигу на базу, т.к. код исполнятся будет ОДИН И ТОТ ЖЕ и в том, и в другом слу4ае. вопрос только в том, 4то при зна4ительных объемах кода писать в ольке на инлайн-асме вру4ную неудобно, для этого и придуман кодинг в шеллкод-стиле
 
Ответить с цитированием
Ответ



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обзор программ для очистки жёсткого диска v1ru$ Soft - Windows 21 17.01.2010 21:07
AVCheck.ru - сервис проверки файлов антивирусами Verified.(zone) Разное - Покупка, продажа, обмен 30 22.12.2009 12:46
Mail.ru запускает сервис хранения файлов green09 Мировые новости 17 19.03.2008 11:47
О взломе лог файлов Frok Чужие Статьи 5 07.03.2006 23:02



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ