Сохранен 23
https://2ch.hk/pr/res/985780.html
24 декабря Архивач восстановлен после серьёзной аварии. К сожалению, значительная часть сохранённых изображений и видео была потеряна. Подробности случившегося. Мы призываем всех неравнодушных помочь нам с восстановлением утраченного контента!

данные из приложения

 Аноним 06/05/17 Суб 13:55:52 #1 №985780 
download.jpg
Научите меня тырить данные из приложения. Суть такова: есть приложение, болеющее проприетарностью, которое умеет показывать смешные кортинки и не дающее их сохранять. Задача проста: найти в кишках функции, которые показывают картинки и сохранить эти внутренние буферы в файл в каком-то виде.

Первым делом я взял IDA, нашел stretchDIBits, поставил брейкпоинты, жму в приложении кнопку - картинка не отображается, пока не сделаю следующий шаг. Отлично. Осталось найти функцию, которая посылает в это место. А НЕТУ этого места, в xref или пустота или явно не то, что нужно. Похоже переход идет по указателю. Как такое искать?

Затем я начал искать сигнатуры. Так как кортинки явно в цветовом пространстве YUV, а монитор в RGB, то где-то должна быть конверсия. На удачу начал искать коэфициенты вида 0.337633 и что сука характерно, нашел их. Но опять, откуда вызывается эта конверсия и куда идет - непонятно, xref ничего не дал.

Я не знаю на чем оно написано, внутри рантаймы С и С++ одновременно. И вообще дохуя либ в статике, навроде zlib. Как парсить структуры? Где про это почитать? Смотреть где?

В общем, хочу научиться разбираться в data flow, а то я по сигнатурам уже дохуя всего накопал, но вот где волшебные буфера с сырыми данными - непонятно.
sageАноним 06/05/17 Суб 14:07:33 #2 №985788 
>>985780 (OP)
Не проще трафик проснифать и спарсить эти кортинки?
Аноним 07/05/17 Вск 03:28:18 #3 №986202 
>>985788
В этом и дело, что трафик тоже болеет проприетарностью, охота сдампить на уровне декодера
Аноним 07/05/17 Вск 03:36:09 #4 №986204 
>>985780 (OP)
> Осталось найти функцию, которая посылает в это место.
Посмотри в дебаггере адрес возврата.
Аноним 07/05/17 Вск 04:33:25 #5 №986209 
png1.png
>>986204
С этим уже начинаются трудности. Слева поставлен брейк на "возможно пнг", клацаем на адрес в стеквью и переходим... Чуть дальше possible_main_decoder. Дело в том, что в possible_main_decoder лишь голый свитч, потому компилятор явно оптимизировал адрес возврата. Стоп! По какой-то причине используются джампы, а не коллы. Потому и адреса "possible_main_decoder" в стеке нет. В общем, хуйня какая-то. А самое главное, оно вызывается 2 раза, хотя должно один раз.

Энивей, как данные выковырять? Я очень слабо представляю что делать дальше.
sageАноним 07/05/17 Вск 08:12:06 #6 №986220 
>>985780 (OP)
>>986209
Скинул бы файл, что ли. По тем полутора инструкциям со скриншота нихуя не понятно.

> Я не знаю на чем оно написано
C/C++, это нормально. Компилятор из Visual Studio, точную версию можешь узнать, посмотрев версию линкера в заголовках PE, алсо, можешь взять какой-нибудь парсер Rich-сигнатур еще, и им тоже посмотреть (https://github.com/dishather/richprint/ но лучше что-нибудь более актуальное).

> Задача проста: найти в кишках функции, которые показывают картинки и сохранить эти внутренние буферы в файл в каком-то виде.
Чем тебя функция, вызывающая StretchDIBits не устроила? Все данные есть, картинка декодирована.

> Я очень слабо представляю что делать дальше.
Сформулируй еще раз, чего ты хочешь добиться.

Нагугли/зделой (тем же компилятором, ключики тоже поподбираешь) FLIRT-сигнатуры для zlib/libpng и т. д.

0x502370 - метод класса, который вызывает другие методы класса (this передается через ecx). Поищи таблицу виртуальных функций, поищи другие методы класса, разберись, что они делают. А главное, посмотри, что лежит в памяти по ecx. Если это декодер, там должен быть указатель на сырой буфер.
Аноним 07/05/17 Вск 10:00:49 #7 №986235 
>>986209
Ничего не понял, как две картинки вообще связаны... Оптимизация адреса возврата это сильно сказано, такого почти никогда не бывает, скорее всего, ты что-то не так понял.
sageАноним 07/05/17 Вск 12:11:26 #8 №986264 
>>986235
> такого почти никогда не бывает
Он имеет в виду:

foo:
...
call bar
...
retn

bar:
...
jmp baz

baz:
...
retn

И это делает каждый уважающий себя компилятор для tail-call, когда размер возвращаемого значения и количество удаляемых из стека аргументов у вызывающей и вызываемой функций совпадают - это дешевле, экономится один retn и экономится время на выполнение этого retn, доступ к стеку и т. д. - возврат из baz в примере выше идет сразу в foo.
Аноним 07/05/17 Вск 12:22:58 #9 №986268 
png2.png
>>986220
>Скинул бы файл, что ли
Ну, я хочу сам научиться.

>Компилятор из Visual Studio
А как ты задетектил? Вот скриншот парсилки

>Чем тебя функция, вызывающая StretchDIBits не устроила? Все данные есть, картинка декодирована.
Тем, что картинка уже декодирована и мне нужно будет ее сжимать самому, а это занятие не быстрое. Да и всегда хочется взять исходник, без экранных оверлеев с копирайтами. А видео как тырить? Нет, это конечно вариант на крайний случай. А я не смогу даже отсюда выцепить буфер.

>Сформулируй еще раз, чего ты хочешь добиться.
Есть приложение со смешными картинками и видео (или даже не приложение, а dll/so, но я пока решил упростить себе задачу, так как не представляю как такое дебажить), где-то внутри него есть декодеры PNG/JPEG/mp4, h264. Кто знает, что там еще есть, но перечисленное - точно, что подтверждается сигнатурами внутри. Так как данные могут быть зашифрованы, то через какие контейнеры оно проходит - неизвестно. Я исхожу из предположения, что если даже нормального mp4 там нет (оно не используется при доставке), то хоть h264 там должен быть не изуродованный. Потому в худщем случае просто дергаем буфера на входе декодера.

Так как я ничего не умею, то слабо представляю, что делать с найденными оффсетами. Сливать ли данные через сокет, или нагло открыть еще тредик и дампать все найденное на диск в своем формате, а дальше уж как-то разберемся в оффлайне? Да и как влезать в процесс тоже большой вопрос, особенно если оно будет в виде dll/so.

>Нагугли/зделой (тем же компилятором, ключики тоже поподбираешь) FLIRT-сигнатуры для zlib/libpng и т. д.
Спасибо, zlib я нашел просто по сигнатурам. По поводу других вещей - меня берет сомнение, что они использовали что-то открытое, особенно для видео, вангую что внутри анальнолицензированное говно от маинконцепта.

>Поищи таблицу виртуальных функций, поищи другие методы класса, разберись, что они делают
Буду признателен за гайд
Аноним 07/05/17 Вск 12:33:35 #10 №986271 
>>986268
Про цель не дописал: все эти смешные картинки, видео и что там еще попадется, потом сохранить в человеческие форматы и сделать релиз всего этого добра на торрентах, во славу прогрессивного человечества. Контент, как было сказано, болеет проприетарностью, потому лучше сдамить за 1 раз хоть как-то, чтобы не тратить деньги. А лучше выпустить все это в виде удобной тулзы, которая залезет в процесс и сделает приятно, чтобы люди всей земли тоже могли делать замечательные релизы (и надеяться, что копирасты ничего не сломают в будущем).
sageАноним 07/05/17 Вск 21:59:54 #11 №986541 
>>986268
> Ну, я хочу сам научиться.
Сложно что-то советовать, не видя программу.

> А как ты задетектил?
Это не я, это IDA. __security_cookie же.

> Вот скриншот парсилки
Теперь ты знаешь, чем конкретно это собиралось (LNK), и знаешь, что собиралось с чужими готовыми билдами каких-то либ (кроме компилятора, который собирал финальный бинарник, засветились компиляторы, которыми собирались либы).

> что делать с найденными оффсетами
Я бы разобрал класс, который управляет декодерами. Похукай его методы и дампи в файлы, нахуя огород с сокетами городить, да еще в чужом процессе?

> Буду признателен за гайд
Начинать лучше с этого, оно до сих пор актуально: https://www.blackhat.com/presentations/bh-dc-07/Sabanal_Yason/Paper/bh-dc-07-Sabanal_Yason-WP.pdf
Вкратце: берешь метод и ищешь, кого он вызывает, и кто его вызывает с тем же this. В рантайме можешь посмотреть первый дворд по this - он будет указывать на таблицу виртуальных функций. По ссылкам на таблицу виртуальных функций из секции кода найдешь конструктор класса. Студия не слишком новая, оптимизаций линкером там немного, поэтому методы будут где-то рядом. По вызовам конструктора/конструкторов найдешь где создаются объекты класса, увидишь там new, узнаешь размер объекта, создашь структуру рекомендую сразу делать тройки струкур Classname_Vtable, Classname_Fields, Classname, чтобы не было мучительно больно, когда натолкнешься на наследование. Главное, не лениться создавать типы и прописывать прототипы функциям. Алсо, существуют всякие плагины типа HexRaysCodeExplorer и прочие ClassInformer, которые слегка помогают.

> Да и как влезать в процесс тоже большой вопрос
CreateToolhelp32Snapshot, чтобы найти процесс с нужной длл, CreateRemoteThread, чтобы поинжектить длл. Все гуглится.
Аноним 08/05/17 Пнд 00:45:10 #12 №986624 
>>986264
Ну так это tail-call, он не так часто встречается (в нормальных функциях), кроме этого, ОП говорит что там какой-то свитч (почему). В любом случае, проблем с xref не бывает почти никогда.
sageАноним 08/05/17 Пнд 00:55:04 #13 №986628 
>>986624
> он не так часто встречается
bool Decoder::decode(Image& target) {
switch (m_type) {
case FILE_TYPE_PNG:
return decode_png(target);
case FILE_TYPE_JPG:
return decode_jpeg(target);
default:
return false;
}
}
Гадание на вымышленном бинаринике, лол
Аноним 08/05/17 Пнд 01:17:20 #14 №986636 
>>986628
Смысл понимаю, но никогда подобного случая tail-call сам не встречал. Впрочем, возможно.
Без бинаря действительно трудно обсуждать, что там происходит.
Аноним 08/05/17 Пнд 08:07:20 #15 №986689 
>>986628
Именно это Ида мне и выдала.
Аноним 08/05/17 Пнд 08:19:44 #16 №986691 
>>986541
>Я бы разобрал класс, который управляет декодерами. Похукай его методы и дампи в файлы, нахуя огород с сокетами городить, да еще в чужом процессе?
Ну у меня просто опыта с этим совсем нет, просто по привычке решил сделать IPC через сокеты. А разбирать как, что будет моей целью?

>чтобы не было мучительно больно, когда натолкнешься на наследование
Т.е. найти оффсеты нужного кода в бинарнике и запатчить их джампами на мой код - это слишком оптимистично, надо обязательно разворачивать до состояния высокоуровневых объектов?

>CreateToolhelp32Snapshot, чтобы найти процесс с нужной длл, CreateRemoteThread, чтобы поинжектить длл. Все гуглится.
Ну найти чужой процесс - это просто, это я умею. Про CreateRemoteThread вроде тоже понятно, но не ясно что делать дальше. Я так вижу это так:
0. Происходит подгрузка моей dll и происходит релокация
1. При старте кода из моей библиотеки, я ищу сам себя в памяти и кусочки кода основного процесса.
2. Найдя нужную сигнатуру в коде софтины, я начало этой функции переписываю на джамп в какую-то рандомную область памяти, а в этой рандомной области делаю stdcall своего кода, который нашел до этого после релокации, который красиво мне сохранит все нужное, вернет управление, а дальше я восстановлю регистры и остаток затертого кода.

Остается только начать смотреть картинки и все будет хорошо, так? Или я что-то понял неправильно или слишком сложно?
sageАноним 08/05/17 Пнд 10:51:53 #17 №986720 
> А разбирать как, что будет моей целью
> надо обязательно разворачивать до состояния высокоуровневых объектов
Только слегка, чтобы примерно понимать, что делают методы, которые из них тебе нужны, какие там аргументы, и где лежат нужные тебе члены класса (ну, размер там какой-нибудь, метаданные и т. п.). А потом да, джампы, красивые реализации нужных методов с возвратом в оригинальные.

> кусочки кода основного процесса
Да, адресуешь RVA относительно базы той дллки, что ты реверсишь (если тебе для одной версии) или ищешь по сигнатурам (если хочешь, чтобы оно пыталось работать на будущих версиях тоже).

> в этой рандомной области делаю stdcall своего кода
Для студии есть хак с __fastcall, чтобы не транслировать конвенции вызовов. Пусть у тебя есть оригинальный метод:
int __thiscall class::method(неявный указатель на this<ecx>, int foo, int bar);
для хука делаешь:
int __fastcall method(void ptr this, int unused, int foo, int bar);
Аргументы у __fastcall летят сначала в ecx/edx, потом в стек, таким образом ты получаешь this, получаешь аргументы, а мусор в edx просто игнорируешь. Можно генерить call сразу в твою длл без дополнительной области памяти.

> восстановлю регистры и остаток затертого кода
Это старый плохой способ, чреватый race condition. По-хорошему нужно взять дизасм длин (можно что-нибудь старенькое и мелкое типа LDE32), скопировать минимально необходимое целое число инструкций, поправить там relative jmp/call (если есть), в конец воткнуть jmp на продолжение в исходном файле, и получится полноценный трамплин, который можно опять же объявить как fastcall и вызывать в конце своего метода, не заботясь о восстановлении регистров (ну т.е., return original_method_head(this, 0, foo, bar)). Но это все прокатывает для кода, собранного старыми компиляторами. В новых компилятор с линкером играют регистрами, как им удобно, и о каких-то конвенциях при вызове внутренних функций говорить не приходится.

Конкретнее я бы сказал при наличии бинарника. Может быть, там методы виртуальные, и достаточно просто и тупо запатчить таблицу виртуальных функций. Может быть, проще найти не сам метод, а его вызов, и патчить сразу вызов безо всех этих анальных плясок со сплайсом начала метода. Может, проще написать кастомный отладчик или самоотладку, натыкать брейкпоинтов и вообще ничего не патчить.
Аноним 08/05/17 Пнд 12:06:43 #18 №986733 
>>986541
>Начинать лучше с этого, оно до сих пор актуально: https://www.blackhat.com/presentations/bh-dc-07/Sabanal_Yason/Paper/bh-dc-07-Sabanal_Yason-WP.pdf
Достаточно интересно, но похоже, что мне рано читать такие книжки. Уровень моего понимания написанного, крайне низкий. Например, почему здесь такое зацикливание на регистре ecx? Это какое-то соглашение, что this == ecx? Или просто так делает Студия и потому такое предположение?

Из практической пользы, я тут только нашел ссылки на готовый тул x86_RE_lib.zip, которого уже нет. Можно найти что-то вроде https://github.com/digitalbond/IBAL, но уже непонятно нужно оно мне или нет. Скачал с вебархива, до кучи нашел ихний БинНави, буду пробовать все это.

>>986720
>Только слегка, чтобы примерно понимать, что делают методы, которые из них тебе нужны, какие там аргументы, и где лежат нужные тебе члены класса (ну, размер там какой-нибудь, метаданные и т. п.).
А разве для этого не достаточно, к примеру, разбора сигнатур файла? К примеру, если есть референс к строчке IHDR, то дальше можно ничего не искать - наш клиент. Поискать только длинну, как далеко можно лазить, а то и просто понадеяться на IEND и шпарить до него.

>Да, адресуешь RVA относительно базы той дллки
Но ведь код может быть загружен в разные места, не? Без поиска не обойтись, не?

>для хука делаешь:
>int __fastcall method(void ptr this, int unused, int foo, int bar);
Это ведь можно будет собрать только студией?

>чреватый race condition
А ему откуда взяться? Если бы мы восстанавливали код на том месте, где только что были - да, а так код затирается один раз, когда загружается библиотека.

>Конкретнее я бы сказал при наличии бинарника
Ладно, сдаюсь: это адобовский флеш (версия в общем-то и не нужна, так как он постоянно обновляется). Я мучаю стенд-элон плеер, как более простой вариант, а вообще оно обычно в виде отдельного процесса-сендбокса в браузере. Флеш умеет подгружать нативные дрм-модули, как оно работает - я плохо представляю. При попытке подменить сертификаты и банально подампать трафик - удалось сдампать много метаинтформации, вроде субтитров, а вот кино было в виде какого-то нечитаемого блоба без известных мне сигнатур. Происходило это на Гуглоплее. Нет, надобности уже нет, но была какая-то обида и появилось желание заиметь универсальный тул, не с экрана же писать, как делают некоторые. Тем более, что некоторые флеш-грабберы именно что лазиют в процесс браузера/плеера, что и натолкнуло меня на идею.
Аноним 08/05/17 Пнд 12:30:35 #19 №986746 
>>985780 (OP)
Если нет приложухи в опен сорсе - не получится. Можешь поебаться с декомпиляторами, но в итоге у тебя получится хуй.
sageАноним 08/05/17 Пнд 12:51:34 #20 №986757 
>>986733
> Это какое-то соглашение, что this == ecx?
Да. Погугли x86 calling conventions.

> А разве для этого не достаточно, к примеру, разбора сигнатур файла?
Достаточно. Но, может быть, там только проверка хедера, к примеру, а декодирование вообще поточное, и данные по мере получения скармливаются злибу. Ну и вообще, я со своей колокольни советую, а я предпочитаю "красиво" интегрироваться в приложение, используя знания о его архитектуре, чтобы было проще поддерживать код. Но ты можешь делать так, как тебе удобнее.

> Но ведь код может быть загружен в разные места, не?
Структура PE-файла достаточно точно описывает, как он будет размещен в памяти. Различаются только базовые адреса (т.е., с какого адреса в памяти размещается первый байт образа). Т.е., если взять адрес из IDA, посчитать RVA (адрес - база), а потом в рантайме к RVA прибавить текущую базу загруженной длл, ты всегда будешь ссылаться на один и тот же байт. Естественно, длл тебе в памяти придется найти. Например, тем же CreateToolhelp32Snapshot(TH32CS_SNAPMODULE).

> Это ведь можно будет собрать только студией?
Ну прямо такого стандарта нет, но gcc/clang на винде __fastcall вполне поддерживают. Ты пользуешься еще каким-то компилятором? Посмотри в документации.

> Если бы мы восстанавливали код на том месте, где только что были - да, а так код затирается один раз
Ты только-только восстановил оригинальный код, и в это время кем-то был вызван метод - ты проебал данные. У тебя инструкция 5 байт, ты только начал восстанавливать код, записал 4 байта, и тут был вызван метод, и процессор прочитал совсем не ту инструкцию, которая должна быть - с большой вероятностью ты уронил программу. Ну это если многопоточность есть.

> адобовский флеш
А пример чего-нибудь под DRM есть бесплатно и удобно? Или что конкретно ты там грабишь?

>>986746
> но в итоге у тебя получится хуй
Наивный чукотский юноша. Люди восстанавливают полный исходный код бинарников, накрытых вмпротектами, транслируют код игрушек под другую архитектуру процессоров, а ты "не получится".
Аноним 08/05/17 Пнд 14:11:13 #21 №986789 
>>986757
>Ты только-только восстановил оригинальный код, и в это время кем-то был вызван метод - ты проебал данные
Нет, я не собираюсь восстанавливать код на прежнем месте. Восстанавливаю его в своем, свежевыделенном участке памяти, а дальше джамп. Т.е. в теории, в момент инъекции, пока картинки еще не показывают, все будет уже закончено.

>А пример чего-нибудь под DRM есть бесплатно и удобно?
play.google.com/store/search?q=free&c=movies
Поищи, тут будут бесплатные мувики. Платные тут же.
В любом случае тебе нужен будет аккаунт и какой-то браузер без нативных дрм, т.е. к примеру старый фокс (eme-free), только тогда оно соглашается на флеш-плеер.
Еще можно погуглить "Adobe DRM demo", там вообще чернуха порой с бинарниками и прочим.
Аноним 10/05/17 Срд 18:46:55 #22 №988341 
iat1.png
Все сложно. Решил хотя бы через IAT заменить вызов АПИ, так как пишут, что это наиболее простой способ: https://en.wikipedia.org/wiki/Hooking
[code]
void IATfind(const char function, HMODULE module) { //Find the IAT (Import Address Table) entry specific to the given function.
int ip = 0;
if (module == 0)
module = GetModuleHandle(0);
PIMAGE_DOS_HEADER pImgDosHeaders = (PIMAGE_DOS_HEADER)module;
PIMAGE_NT_HEADERS pImgNTHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImgDosHeaders + pImgDosHeaders->e_lfanew);
PIMAGE_IMPORT_DESCRIPTOR pImgImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)pImgDosHeaders + pImgNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

if (pImgDosHeaders->e_magic != IMAGE_DOS_SIGNATURE)
printf("libPE Error : e_magic is no valid DOS signature\n");

for (IMAGE_IMPORT_DESCRIPTOR
iid = pImgImportDesc; iid->Name != NULL; iid++) {
[/code]
IMAGE_IMPORT_DESCRIPTOR в MSDN не описан, а где был - статья прокисла.
Ладно, нагуглил поля, пытался обращаться к iid->Name - на обращении код и дохнет.
(вообще, код у меня толком не компилится, пришлось править, возможно у меня заголовки неправильные)

На скриншоте калькулятор, в который инъектнута библитека через CreateRemoteThread, первый элемент "найденной таблицы" pImgImportDesc указывает на это, поле имени вообще указывает на но-аксесс страницу. Сами имена библиотек, физически, расположены дальше.
Аноним 10/05/17 Срд 22:39:07 #23 №988448 
>>988341
https://en.wikipedia.org/wiki/Relative_Virtual_Address#Relative_virtual_address
В заголовках PE почти нет VA (нормальных указателей), чтобы не приходилось их патчить при загрузке модуля не по родной базе. Вместо них используются RVA (относительные виртуальные адреса), они указывают смещение данных относительно базы модуля, т.е., в твоем коде:
LPCSTR name = (BYTE ∗) module + iid->Name;
comments powered by Disqus

Отзывы и предложения