![]() |
eXeL@B —› Вопросы новичков —› Извлечение массива. Требуется помощь и советы. |
Посл.ответ | Сообщение |
|
Создано: 14 сентября 2009 00:20 · Поправил: uinor · Личное сообщение · #1 Прошу проконсультировать меня, т.к. немного путаюсь. Вводное -- Есть приложение (win32 / native / c++), знаю что где-то расположен массив байт (myArray), знаю, что он передается в качестве одного из параметров в функцию из динамической библиотеки (myFunc, присутствует в таблице импорта приложения). Задача -- Получить массив целиком для своих нужд. Дополнительные условия -- * Обойтись минимальными жертвами (без сторонних дизасмов и прочего) * Высокая скорость работы * Никаких сигнатур не известно, иначе использовал бы binary search * Извлечение статическое * Речь идет не об одном анализируемом приложении, ситуация может меняться (адрес myFunc, положение массива, его размер и прочее). Во всех случаях не меняется лишь общая схема. Подробнее -- Так выглядит массив в исходном коде (исключительно для примера): Code:
Так выглядит вызов функции: Code:
Где, адрес 00414680h указывает на расположение массива (идет последним параметром). Мои размышления 1. Берем таблицу импорта, находим адрес myFunc 2. Находим reference на него, попадаем в импорт(?) (jmp xxx) 3. Находим reference на импорт, попадаем в подпрограмму, приведенную выше 4. Получаем адрес массива, поднимаясь выше (не знаю как грамотно организовать) 5. Переходим по адресу Я не так хорошо знаком с PE форматом, возможно это делается проще. У меня дикая путаница в голове относительно RVA & etc, буду курить материал, очень буду рад, если кто-то даст алгоритм максимально подробно. Как получить размер массива? Как грамотнее подняться до адреса массива в подпрограмме (можно дико захардкодить, но хотелось бы гибкости, ситуации могут быть разные)? ![]() |
|
Создано: 14 сентября 2009 09:38 · Личное сообщение · #2 Пока не очень понятно - задача слишком общая, а уж по методам - неясно что вы умеете и какие инструменты будете использовать, значит непонятно как делать. Исходя из слов "извлечение статическое" - самое быстрое в освоении : остановиться отладчиком на вызове функции и сдампить массив. А размышления ваши наводят на мысль, что постановка задачи глобальная : типа написать универсальный "статический" выдиратель(но он будет динамический), но тогда непонятно условие "Обойтись минимальными жертвами (без сторонних дизасмов и прочего)". Ваши размышления правильны, но адрес массива в общем случае без отладчика не получить - в вашем примере адрес просто "зашит" в программу, но так бывает не всегда. ![]() |
|
Создано: 14 сентября 2009 12:14 · Личное сообщение · #3 |
|
Создано: 14 сентября 2009 12:39 · Личное сообщение · #4 А чем тогда способ с отладчиком не устраивает. Если нужно самому сделать - освой написание лоадера. Можно сделать патч и сбрасывать массив в файл - тоже вариант. Или у тебя задача другая : в разных вариантах проги найти вызов этой подпрограммы, потом найти адрес самого массива, а читать ты его уже умеешь? ![]() |
|
Создано: 14 сентября 2009 13:04 · Личное сообщение · #5 |
|
Создано: 14 сентября 2009 14:25 · Поправил: tundra37 · Личное сообщение · #6 Тогда по порядку, раз не хочешь самое простое с отладчиком: 1) Размер массива можно определить только зная конкретику про MyFunc. Он может быть в параметрах, если повезет, а может быть где угодно ![]() 2) Таблица импорта. Это легко сказать - все зависит от того на чем компилили. Импорт функции найти легко, но там может быть просто jump и ..... найти можно, но по разному. 3) Дальше все уже проще, если конечно слова про 99% верны - смотрим СООТВЕТСТВУЮЩИЙ адрес в exe и в данном случае по-моему там всего надо 400000 добавить. И из СООТВЕТСТВУЮЩЕГО адреса(используем таблицу секций) берем наш массив. Про длину я уже писал. Это конечно, если содержимое массива забито в exe, а не заполняется в процессе работы. А КТО СКАЗАЛ, что будет легко. Вот отладчик это все сделает без напряга, кроме конечно обнаружения call на автомате. А если взять нормальную Ольгу можно и защищенные проги "драть". Если все статично на 99%, то проще найти сигнатуру соседей call MyFunc или даже лучше самого массива - программа простая будет до ужаса. ![]() |
|
Создано: 14 сентября 2009 18:33 · Личное сообщение · #7 tundra37 вы видели дефиницию массива? В параметрах размер не передается. Чтоб его размерность где-либо хранилась тоже не видел. Импорт без заморочек. Имя функции есть, тут все нормуль. Вариант с парсом заголовка и нахождением адреса переходника рассматриваем? Или иначе стоит подойти? Содержимое массива заполнено еще в стадии разработки. Оно не меняется в процессе работы. Отладчиком я путь прошел без проблем. Тут даже отладчик не нужен, хватает дизасма и пары переходов по рефам, описал в первом же посте момент. Вытаскивается на ура. Относительно сигнатуры. Массив вычислить никак не получится. Контент непредсказуем. Поясните что имели в виду относительно соседей myFunc? Допустим, по маске я нашел тело подпрограммы с вызовом myFunc, вычленил адрес массива. Как его преобразовать в оффсет файла по которому лежит массив? ![]() |
|
Создано: 14 сентября 2009 20:58 · Личное сообщение · #8 uinor пишет: Как его преобразовать в оффсет файла по которому лежит массив? а зачем его преобразовывать?можно же прямо в ольге сохранить кусок данных в файл. и вполне возможно что размер массива может в первом двойном слове содержаться если это структура. помнится вроде про рва в туторах ICZELION'a есть ![]() |
|
Создано: 15 сентября 2009 08:37 · Поправил: uinor · Личное сообщение · #9 Стоп, речь идет о статическом анализе + полная автоматика. Вытащить массив действуя руками в дизассемблере - тривиально. Я прошу помощи именно в плане автоматизации этой работы. Давайте рассмотрим вариант с binary search, хотя судя по экспериментам проблематично будет сделать сигнатуру для поиска вызова myFunc и получения адреса массива. Есть предложения по сигнатуре? Далее, что делать с адресом массива (00414680h)? Это RVA? Следовательно остается просто RVA2Offset и вытащить массив? Размер действительно лежит в первом двойном слове, благодарю. ![]() |
|
Создано: 15 сентября 2009 10:52 · Поправил: tundra37 · Личное сообщение · #10 uinor С такими знаниями и подходами вы далеко пойдете. В 8:57 ваш "напарник"(а может альтерэго) написал на wasm.ru, что длина лежит по указателю. А если ваш пример взят из "жизни", то там лежит строка (сейчас не вспомню как этот тип зовется): в первом слове длина и далее сам ваш массив. Можно найти вообще все такие строки и даже исходники найти для этого, но это не метод сигнатур. Использования лоадера никак не означает динамики : после загрузки вашего exe не обязательно его выполнять, а можно просто(гораздо проще чем из файла-exe) найти вызов функции и ее параметры и массив извлечь прямо по адресу, а не пересчитывать "страшные" RVA. А вы пытаетесь повторить часть загрузчика или часть дизассемблера - это гораздо сложнее. Если же ваша цель именно научиться, то тогда увы - одними советами тут точно не обойтись, даже всех профи с краклаба и васма. ![]() |
|
Создано: 15 сентября 2009 11:10 · Личное сообщение · #11 tundra37, позвольте. Во-первых, первым dword'ом; во-вторых оно там лежит не случайно и будет лежать всегда. Увидел это достаточно случайно, чему рад. Это массив, я в первом же посте приводил оригинальный код, который в последствие компилируется. "Строка" лежит лишь в моем примере (специально не стал преобразовывать char'ами, а выдал hex'е, чтоб это не сбивало никого с толку. Спасибо относительно разъяснений по поводу лоадера. Т.е. запуска при этом не происходит? Таким же принципом судя по всему поступает PE Explorer? Как происходит загрузка исполняемого файла и дальнейшая работа с ним (если ориентируемся на форм-фактор loader'a)? Подскажите пару ключевых слов, постараюсь разобраться. Интересно было бы увидеть примеры, конечно. ![]() |
|
Создано: 15 сентября 2009 12:20 · Личное сообщение · #12 А вот чтобы не было случайностей достаточно было в отладчике пробежать обработчик и вы бы увидели длину ![]() Теперь про лоадер - какие-то исходики были здесь. Где - фиг знает. Есть лоадеры без исходников, но с возможностью "программирования". И о вкусах конечно не спорят, но ваше желание сделать автомат плохо подкреплено знаниями. ![]() |
|
Создано: 15 сентября 2009 12:45 · Личное сообщение · #13 tundra37, я пробегал в отладчике и не только, вы не поверите. Этот массив кодогенерируется, там просто некий контент (я специально вставил туда метку, чтоб быстро найти его в коде). Чтоб первым двордом лежит длина - нетривиально, но можно заметить ![]() Мне достаточно понять принцип. tundra37, я специализируюсь на форматах данных (DRE) + разработка ПО непосредственно, к сожалению, многие техники RE мне недоступны. ![]() |
|
Создано: 15 сентября 2009 13:38 · Личное сообщение · #14 tundra37, вы под лоадером имели в виду mapping с флагом SEC_IMAGE? это меняет дело, понял ситуацию. просто запросы по loader'у & etc выводили на совершенно другие моменты. Да, действительно это удобно (использование механизмов самой ОС в плане проецирования с целью дальнейшего "удобного" использования). ![]() |
|
Создано: 16 сентября 2009 10:11 · Поправил: tundra37 · Личное сообщение · #15 Это ты уже полез вдебри. Исходники никто не торопится дать, а искать лень. Давай попытаемся превратить твои размышления + мои в некий план действий. 1) Исходник лоадера собственно и не нужен. exe загружает в память какая-то системная функция и наверняка она где-то на сайте описана. Другой вариант: запустить exe на выполнение, предварительно пропатчив точку входа "бесконечным jump-ом". 2) Далее придется самому реализовать упрощенный дизассемблер : искать команды call, отбраковывать "ложные" команды call, по адресу забитому в call добираться до таблицы импорта и находить нашу функцию. 3) Зная нужную команду call поднимаемся немного выше по адресам и выуживаем адрес массива. Если других вариаций вызова кроме 2-х указанных на васм нет - это просто. Если нет: обработав все N приложений использующих функу из DLL получим K поиска адреса массива. 4) Извлекаем по адресу наш массив и все - задача решена. Теперь оценим трудности для вас в реализации: 1) находим инфу и относительно легко реализуем. Такой функционал писали многие неленивые новички. 2) реализация этого пункта потребует "помощи зала" или кропотливого изучения. 3) Это уже детский сад после 1 и 2, ну в варианте с запуском exe немного мук с чтением памяти процесса. Есть другой вариант, который вы изначально пробиваете : работать с exe-файлом. Все тоже самое, только добавляются сложности проецирования данных найденных в импорте и в секции команд на exe-файл. Это еще сложнее получается. Если отказаться от автомата, то есть легкий путь, который вам и предлагали : 1) Грузим в olly ваше приложение и выбираем в контекстном меню поиск по именам внешних функций. Найдя ее открываем пункт "поиск вызовов"(пишу по памяти, готов все нарисовать если будет подопытный кролик). Далее открываем найденный вызов в дизассемблере (ой вы не хотели...) , поднимаемся на две команды, открываем массив и легким кликом копируем куда надо. olly имеет язык скриптов и можно это все автоматизировать. Сама olly небольшая и можно таскать на место поиска совершенно свободно. Есть другой вариант - использовать дизассемблер, но IDA относительно тяжеловесна и по времени это дольше. Скрипты там тоже есть, но по сравнению с olly по-моему тяжелее в освоении. Это я к тому, что скрипты olly я могу вам написать, а для IDA не гарантирую. Если есть быстрый дизассемблер, который нормально определяет вызов вашей функции, то можно написать простенький анализатор его выдачи для выдирания вашего массива - чем не автомат. Выбор за вами. Но поверьте человеку, который вникает в проблемы крака уже не один год, написание автомата самому - это работа на год или вам придется все бросить и углубленно изучать PE-формат. ![]() |
|
Создано: 16 сентября 2009 17:14 · Поправил: _ruzmaz_ · Личное сообщение · #16 |
|
Создано: 16 сентября 2009 18:44 · Поправил: uinor · Личное сообщение · #17 _ruzmaz_, нужна статика, тут сплайс мимо. Вроде ситуация решена, остался последний момент с вычленением адреса массива из параметра. Подключил мелкий и быстрый дизасм длин, осталось теперь только определиться со схемой работы. Вот, кстати, лог с утильки (D2007, грязновато, но все же): Code:
![]() |
|
Создано: 16 сентября 2009 19:25 · Личное сообщение · #18 |
|
Создано: 16 сентября 2009 19:37 · Личное сообщение · #19 _ruzmaz_, я понимаю это отлично ) Речь идет о том, что там может быть проталкивание параметров не только через регистры, но и через стэк (via push), поэтому варианта два, либо накладывать какую-то гибкую маску, либо анализировать детально что-куда-как (предусматривая некую библиотеку вариантов). Может мысли будут по оптимальной схеме какие? ![]() |
|
Создано: 16 сентября 2009 20:02 · Поправил: _ruzmaz_ · Личное сообщение · #20 |
|
Создано: 16 сентября 2009 20:45 · Личное сообщение · #21 |
|
Создано: 16 сентября 2009 23:03 · Личное сообщение · #22 |
![]() |
eXeL@B —› Вопросы новичков —› Извлечение массива. Требуется помощь и советы. |
Эта тема закрыта. Ответы больше не принимаются. |