Хакер - Мертвая эра. Изучаем приложение, созданное в BioEra

Хакер - Мертвая эра. Изучаем приложение, созданное в BioEra

hacker_frei

https://t.me/hacker_frei

МВК

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

Этой стать­ей я про­дол­жаю тему визу­аль­ного прог­рамми­рова­ния, свое отно­шение к которо­му я уже под­робно и исчерпы­вающе выразил в статье с говоря­щим наз­вани­ем «Пол­ное G. Лома­ем при­ложе­ние на язы­ке G, соз­данное в LabVIEW». А что, если прог­рамму из этой статьи написать на Java, потом час­тично ском­пилиро­вать, а час­тично — зашиф­ровать код? Получит­ся соф­тина, соб­ранная с исполь­зовани­ем про­екта BioEra!

Из информа­ции на сай­те (име­ющем весь­ма спар­тан­ский дизайн, как и сама сре­да прог­рамми­рова­ния) мож­но узнать, что инс­тру­мент поз­воля­ет соз­давать кросс‑плат­формен­ные при­ложе­ния для обра­бот­ки сиг­налов с дат­чиков и игро­вых кон­трол­леров. Еще в BioEra мож­но раз­рабаты­вать софт для обра­бот­ки зву­ка, что харак­терно, абсо­лют­но не имея навыков прог­рамми­рова­ния — как раз то, что нуж­но сов­ремен­ному начина­юще­му кодеру!

WARNING

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

Да­бы не нарушать законы, ска­чаем с сай­та три­аль­ную вер­сию этой сре­ды раз­работ­ки и поп­робу­ем решить прос­тую задачу: обой­ти пароль­ную защиту на редак­тирова­ние ском­пилиро­ван­ных в BioEra фай­лов визу­аль­ных про­ектов .BPD (раз­работ­чики гор­до называ­ют их «дизай­нами»). Как и в любой дру­гой сре­де раз­работ­ки visual programming language (типа LabView), про­ект тут в пря­мом смыс­ле рису­ется в визу­аль­ном редак­торе в виде блок‑схе­мы.

Ра­зуме­ется, при такой откры­тос­ти исходни­ков в BioEra сущес­тву­ют спо­собы огра­дить «дизайн» от шалов­ливых ручек хакеров, которым взду­мает­ся дизас­сем­бли­ровать, а то и поп­равить про­ект. Защита тут исполь­зует­ся поп­роще, чем в LabView, но все рав­но мож­но пос­тавить на «дизайн» пароль на откры­тие и редак­тирова­ние визу­аль­ной блок‑схе­мы. Имен­но такую защиту мы и поп­робу­ем обой­ти, ведь это путь к пос­тижению логики пос­тро­ения при­ложе­ний дан­ной сре­ды раз­работ­ки.

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

Итак, смот­рим файл bioera.exe из ска­чан­ного и уста­нов­ленно­го три­ала. DetectItEasy не видит на нем никакой защиты и пред­полага­ет, что при­ложе­ние написа­но на си. Запус­каем его и пыта­емся им открыть запаро­лен­ный дизайн. Выс­какива­ет окош­ко вво­да пароля.

Та­ких строк нет в EXE-фай­ле, более того, их нет вооб­ще ни в одном фай­ле уста­нов­ленно­го пакета, ког­да мы пыта­емся их отыс­кать гло­баль­ным поис­ком. Топор­ный дизайн окон напоми­нает Java, в пакете дей­стви­тель­но обна­ружи­вает­ся великое мно­жес­тво Jar-биб­лиотек, но поиск по их содер­жимому тоже ничего не дает. Атта­чим­ся к запущен­ному про­цес­су при помощи нашего любимо­го отладчи­ка x32dbg и видим, что это не то что­бы сов­сем явная Java, — вир­туаль­ная машина JVM интегри­рова­на пря­мо в EXE-файл. Неч­то подоб­ное я опи­сывал в сво­ей статье «Су­ровая жаба. Изу­чаем защиту Excelsior JET для прог­рамм на Java».

Стек вызовов прер­ванно­го про­цес­са

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

Поп­робу­ем подой­ти к решению задачи с дру­гой сто­роны: отсле­дим фай­лы, к которым при­ложе­ние обра­щает­ся при заг­рузке. Для это­го запус­каем ути­литу Process Monitor (ProcMon), уста­нав­лива­ем филь­тр на про­цесс bioera.exe и отсле­жива­ем все его обра­щения к фай­ловой сис­теме. Очень неп­ростое решение, пос­коль­ку мы по опы­ту уже зна­ем, нас­коль­ко длин­ные прос­тыни обра­щений к самым раз­ным фай­лам нам при­дет­ся отсле­живать в резуль­тате.

В нашем слу­чае самым глав­ным кан­дидатом на вмес­тилище кода будет доволь­но уве­сис­тый файл be.cbe из под­катало­га \ext, который гру­зит­ся в память целиком пос­ледова­тель­ными пор­циями по 65 535 (0xFFFF) байт. При бег­лом прос­мотре этот файл (за исклю­чени­ем 5-бай­тового заголов­ка CBE01) пред­став­ляет собой уме­рен­но энтро­пичес­кую кашу из сим­волов — он явно упа­кован или зашиф­рован каким‑то алго­рит­мом собс­твен­ного изоб­ретения.

Ну что ж, поп­робу­ем его изу­чить. Для это­го сно­ва заг­ружа­ем отладчик x32dbg и запус­каем отту­да файл bioera.exe, пред­варитель­но уста­новив условную точ­ку оста­нова на ReadFile с усло­вием оста­нов­ки [esp+0xC]==0x0FFFF. В пер­вый раз нас ждет осеч­ка — прог­рамма в отладчи­ке завер­шает­ся, не дос­тигнув точ­ки оста­нова. Одна­ко на экра­не окно прог­раммы все‑таки заг­рузилось, уже вне отладчи­ка.

Про­буем при­атта­чить­ся к ее про­цес­су и видим, что прог­рамма прос­то перезаг­рузила сама себя со сле­дующи­ми парамет­рами коман­дной стро­ки:

"C:\Program Files (x86)\BioEraTrial\bioera.exe" launcher -root C:\Program%20Files%20(x86)\BioEraTrial\ -j15

Ме­няем в x32dbg коман­дную стро­ку на эту и сно­ва запус­каем при­ложе­ние. На этот раз точ­ка оста­нова сра­баты­вает. Иско­мый вызов из  — это стан­дар­тный Java- заг­рузчик задан­ного количес­тва бай­тов из фай­ла:

<_Java_java_io_FileInputStream_readBytes@20>

Поп­робу­ем отсле­дить даль­нейшую судь­бу про­читан­ных с его помощью бай­тов. Эта задача будет чуть пос­ложнее. Для начала ста­вим точ­ку оста­нова на дос­туп к какому‑нибудь бай­ту из све­жес­читан­ного буфера. Про­читан­ные бай­ты будут нес­коль­ко раз переме­щать­ся из мас­сива в мас­сив, и каж­дый раз при­дет­ся уби­рать аппа­рат­ную точ­ку оста­нова в преж­ней локации и перес­тавлять ее на новое мес­то. В кон­це кон­цов наши уси­лия увен­чива­ются успе­хом: нуж­ный байт выбира­ется из мас­сива из ском­пилиро­ван­ного JVM-кода:

movsx ebx,byte ptr ds:[edx+eax+C]

mov eax,ebx ; eax <- считанный из буфера байт

movzx ebx,byte ptr ds:[esi+1] ; esi — указатель на следующий JVM-опкод, который загружается в ebx

inc esi ; Следующий опкод в esi

jmp dword ptr ds:[ebx*4+6DA6C148] ; Переход на обработчик следующего опкода

Как видим, в нашей вер­сии при­ложе­ния реали­зова­на доволь­но при­митив­ная 32-бит­ная Java-машина. JVM-код даже не ском­пилиро­ван, а прос­то интер­пре­тиру­ется в про­цес­се выпол­нения, чем объ­ясня­ется изрядная непово­рот­ливость прог­раммы. В прин­ципе, если у тебя есть в запасе уйма сво­бод­ного вре­мени, ты можешь дизас­сем­бли­ровать алго­ритм рас­шифров­ки, поп­рыгав в отладчи­ке по коду, но мы пос­тупим про­ще. Ведь это не какие‑нибудь Themida или VMProtect, а впол­не зауряд­ная и широко извес­тная JVM, ее сис­тема команд задоку­мен­тирова­на, и у нас в регис­тре esi есть адрес на исполня­емый в дан­ный момент шитый код.

Стек вызовов прер­ванно­го про­цес­са

К при­меру, код текущей исполня­емой инс­трук­ции (обра­бот­чик которой при­веден выше, на скрин­шоте jy выделен крас­ным) — 33h, это baload. Мож­но даже уга­дать имя исполня­емо­го метода (decode) и его класс (be.read.Cipher). Оста­лось толь­ко най­ти этот класс и по‑челове­чес­ки деком­пилиро­вать.

К сожале­нию, гло­баль­ным поис­ком нуж­ный нам класс тоже не находит­ся. Похоже, мы выш­ли на ядро какого‑то более глу­боко­го уров­ня, копать который по опи­сан­ному выше методу нам уже надо­ело и неин­терес­но. Поэто­му на этот раз мы схал­турим — прос­то най­дем этот класс в исходном виде в памяти про­цес­са по шаб­лону (ска­жем, тот же be/read/Cipher) и сдам­пим его в файл, начиная с сиг­натуры CAFEBABE.

Стек вызовов прер­ванно­го про­цес­са

Де­ком­пилиро­вав этот класс, мы получа­ем исполь­зуемые в BioEra алго­рит­мы шиф­рования и дешиф­рования. Они совер­шенно при­митив­ны, хотя чуть слож­нее по исполне­нию обыч­ного XOR:

package be.read;

public class Cipher {

public static final int LEN = 311;

static final int BIGLEN = 79616;

protected byte[] buffer = new byte[311];

private byte[] eb = new byte[311];

static final int k1 = 19;

static final int k2 = 236;

protected void decrypt() {

int i = 311;

while (--i >= 0) {

this.eb[i] = (byte)((this.buffer[i] & 0x13) + (this.buffer[(i + 7) % 311] & 0xEC));

}

i = 311;

while (--i >= 0) {

this.buffer[i] = (byte)(this.eb[i] - i * 13 % 17);

}

}

protected void encrypt() {

int i = 311;

while (--i >= 0) {

this.eb[i] = (byte)(this.buffer[i] + i * 13 % 17);

}

i = 311;

while (--i >= 0) {

this.buffer[i] = (byte)((this.eb[i] & 0x13) + (this.eb[(i - 7 + 79616) % 311] & 0xEC));

}

}

}

Те­перь, ког­да у нас есть эти алго­рит­мы, ком­пилиру­ем прос­тень­кий декодер и рас­шифро­выва­ем им файл be.cbe. В рас­кодиро­ван­ном виде он пред­став­ляет собой пос­ледова­тель­ность откомпи­лиро­ван­ных и обфусци­рован­ных клас­сов, которые мож­но выделять и отре­зать по сиг­натурам CAFEBABE для деком­пиляции. Поиск по стро­ке "Protected design" выводит нас на класс mF, который, помимо про­вер­ки пароля для защищен­ного дизай­на, содер­жит мно­жес­тво дру­гих вкус­няшек типа про­вер­ки дон­гла, лицен­зии, сиг­натур (в час­тнос­ти, упо­мяну­тый выше сер­висный режим). Но наша задача — обой­ти про­вер­ку пароля. Иско­мое мес­то лег­ко находит­ся в деком­пилиро­ван­ном коде в методе public static final int a(Pi pi, uI uI2, String string) и выг­лядит так:

PF pF = new PF(m.p.J(), "Protected design");

pF.c = true;

if (nE.c()) {

System.out.println("DEV - Skipping nes des pwd dlg");

} else {

pF.b("Password");

}

if (nE.c() || pF.b && pF.q().equals(uI2.l.toString())) // Если убрать эту проверку, то любой введенный пароль будет приниматься как родной

{

m.p.R = false;

rA.f = true;

return 5;

}

Как вид­но из кода, по‑хороше­му мож­но было бы про­пат­чить класс nE.c(), тог­да окно пароля вооб­ще не будет появ­лять­ся, но нам уже все надо­ело и искать, а потом деком­пилиро­вать этот класс прос­то лень. Поэто­му берем нашего любимо­го «Гряз­ного Джо» (я писал о нем в статье «Гряз­ный Джо. Взла­мыва­ем Java-при­ложе­ния с помощью dirtyJOE») и ищем пос­ледова­тель­ность опко­дов, соот­ветс­тву­ющих выраже­нию nE.c() внут­ри усло­вия if (...). Выг­лядит это вот так.

Стек вызовов прер­ванно­го про­цес­са

Что­бы условный переход всег­да отра­баты­вал, выделен­ную крас­ным пос­ледова­тель­ность нуж­но заменить true (04). В ито­ге нам надо в рас­шифро­ван­ном фай­ле be.cbe най­ти пос­ледова­тель­ность бай­тов B8 01 B7 9A 00 1D, пер­вые три из которых испра­вить на 00 00 04, а потом зашиф­ровать файл обратно. Про­делы­ваем это и убеж­даем­ся, что теперь защищен­ные дизай­ны откры­вают­ся при вво­де любого пароля безо вся­кого сер­висно­го режима.

ВЫВОДЫ

Воз­можно, читатель упрекнет меня в том, что мы пот­ратили столь­ко вре­мени и сил впус­тую. Ведь, судя по пос­ледним новос­тям на этом сай­те, эта сре­да раз­работ­ки не заво­ева­ла популяр­ности и, ско­рее все­го, не успе­ла рас­пол­зтись по миру. Поэто­му веро­ятность встре­тить­ся с соз­данны­ми при помощи BioEra прог­рамма­ми у читате­ля невысо­ка. Одна­ко мы пре­пари­рова­ли это­го мер­тво­рож­денно­го монс­тра прос­то из люб­ви к экзо­тике и в озна­коми­тель­ных целях — для при­обре­тения опы­та ревер­са нес­тандар­тных Java-при­ложе­ний.

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page