Ҷустуҷӯи осебпазирӣ дар Browser UC

Ҷустуҷӯи осебпазирӣ дар Browser UC

Муқаддима

Дар охири мохи март мо хабар дод, ки онҳо қобилияти пинҳонии бор кардан ва иҷро кардани рамзи тасдиқнашударо дар Browser UC кашф карданд. Имрӯз мо ба таври муфассал дида мебароем, ки ин зеркашӣ чӣ гуна рух медиҳад ва чӣ гуна ҳакерҳо метавонанд онро барои мақсадҳои худ истифода баранд.

Чанде пеш, UC Browser хеле хашмгинона таблиғ ва паҳн карда шуд: он дар дастгоҳҳои корбарон бо истифода аз нармафзори зараровар насб карда шуд, ки аз сайтҳои гуногун зери пардаи файлҳои видеоӣ паҳн карда шуд (яъне корбарон фикр мекарданд, ки онҳо, масалан, видеои порнографиро зеркашӣ мекунанд, аммо ба ҷои ин, APK бо ин браузер гирифта шуд), баннерҳои даҳшатнокро бо паёмҳое истифода бурд, ки браузер кӯҳна, осебпазир ва монанди инҳо буд. Дар гурӯҳи расмии UC Browser дар VK мавҷуд аст мавзӯъ, ки дар он корбарон метавонанд аз таблиғи беадолатона шикоят кунанд, мисолҳои зиёде мавҷуданд. Дар соли 2016 ҳатто вуҷуд дошт рекламаи видеоӣ бо забони русӣ (бале, таблиғ барои браузери бастани таблиғ).

Дар замони навиштан, UC Browser дар Google Play зиёда аз 500 000 000 насб дорад. Ин таъсирбахш аст - танҳо Google Chrome бештар дорад. Дар байни баррасиҳо шумо метавонед шикоятҳои зиёдеро дар бораи таблиғ ва масир ба баъзе замимаҳо дар Google Play дидан мумкин аст. Ин сабаби тадқиқоти мо буд: мо тасмим гирифтем, ки бубинем, ки UC Browser кори бад мекунад. Ва маълум шуд, ки ӯ мекунад!

Дар коди барнома, қобилияти зеркашӣ ва иҷро кардани коди иҷрошаванда кашф карда шуд, ки ба коидахои нашри аризахо мухолиф аст дар Google Play. Илова бар зеркашии коди иҷрошаванда, UC Browser ин корро ба таври ноамн анҷом медиҳад, ки метавонад барои оғози ҳамлаи MitM истифода шавад. Биёед бубинем, ки оё мо чунин ҳамларо анҷом дода метавонем.

Ҳама чизе, ки дар зер навишта шудааст, ба версияи UC Browser, ки дар вақти омӯзиш дар Google Play дастрас буд, мувофиқ аст:

package: com.UCMobile.intl
versionName: 12.10.8.1172
versionCode: 10598
sha1 APK-файла: f5edb2243413c777172f6362876041eb0c3a928c

Вектори ҳамла

Дар манифести UC Browser шумо метавонед хидматеро бо номи худфаъолкунанда пайдо кунед com.uc.deployment.UpgradeDeployService.

    <service android_exported="false" android_name="com.uc.deployment.UpgradeDeployService" android_process=":deploy" />

Вақте ки ин хидмат оғоз мешавад, браузер дархости POST медиҳад puds.ucweb.com/upgrade/index.xhtml, ки онро чанд вакт пас аз огози харакат дар харакат дидан мумкин аст. Дар посух, ӯ метавонад фармонеро гирад, ки ягон навсозӣ ё модули навро зеркашӣ кунад. Ҳангоми таҳлил сервер ин гуна фармонҳоро надодааст, аммо мо пай бурдем, ки вақте ки мо кӯшиш мекунем, ки PDF-ро дар браузер кушоем, он ба суроғаи дар боло зикршуда дархости дуюм мекунад ва пас аз он китобхонаи ватаниро зеркашӣ мекунад. Барои анҷом додани ҳамла, мо тасмим гирифтем, ки ин хусусияти UC Browser -ро истифода барем: қобилияти кушодани PDF бо истифода аз китобхонаи ватанӣ, ки дар APK нест ва агар лозим бошад, онро аз Интернет зеркашӣ мекунад. Қобили зикр аст, ки аз ҷиҳати назариявӣ, UC Browser-ро маҷбур кардан мумкин аст, ки чизеро бе ҳамкории корбар зеркашӣ кунад - агар шумо ба дархосте, ки пас аз ба кор андохтани браузер иҷро мешавад, посухи хубе пешниҳод кунед. Аммо барои ин, мо бояд протоколи ҳамкорӣ бо серверро муфассалтар омӯзем, бинобар ин мо тасмим гирифтем, ки таҳрир кардани посухи боздоштшуда ва иваз кардани китобхона барои кор бо PDF осонтар хоҳад буд.

Ҳамин тавр, вақте ки корбар мехоҳад PDF-ро мустақиман дар браузер кушояд, дар трафик дархостҳои зеринро дидан мумкин аст:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Аввалан дархости POST вуҷуд дорад puds.ucweb.com/upgrade/index.xhtmlбаъд аз он
Архив бо китобхона барои дидани форматҳои PDF ва офис зеркашӣ карда мешавад. Фарз кардан мантиқ аст, ки дархости аввал маълумотро дар бораи система интиқол медиҳад (ҳадди аққал меъморӣ барои таъмин кардани китобхонаи зарурӣ) ва дар посух ба он браузер дар бораи китобхонае, ки бояд зеркашӣ карда шавад, маълумот мегирад: суроға ва эҳтимолан. , чизи дигар. Мушкилот дар он аст, ки ин дархост рамзгузорӣ шудааст.

Фрагментро дархост кунед

Фрагмент ҷавоб

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ҷустуҷӯи осебпазирӣ дар Browser UC

Худи китобхона дар ZIP баста шудааст ва рамзгузорӣ нашудааст.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ҷустуҷӯи рамзи рамзкушоии трафик

Биёед кӯшиш кунем, ки ҷавоби серверро фаҳмем. Биёед рамзи синфро бубинем com.uc.deployment.UpgradeDeployService: аз усул onStartCommand равед com.uc.deployment.bx, ва аз он ба com.uc.browser.core.dcfe:

    public final void e(l arg9) {
int v4_5;
String v3_1;
byte[] v3;
byte[] v1 = null;
if(arg9 == null) {
v3 = v1;
}
else {
v3_1 = arg9.iGX.ipR;
StringBuilder v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]product:");
v4.append(arg9.iGX.ipR);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]version:");
v4.append(arg9.iGX.iEn);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]upgrade_type:");
v4.append(arg9.iGX.mMode);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]force_flag:");
v4.append(arg9.iGX.iEo);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_mode:");
v4.append(arg9.iGX.iDQ);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_type:");
v4.append(arg9.iGX.iEr);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_state:");
v4.append(arg9.iGX.iEp);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_file:");
v4.append(arg9.iGX.iEq);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apk_md5:");
v4.append(arg9.iGX.iEl);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_type:");
v4.append(arg9.mDownloadType);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_group:");
v4.append(arg9.mDownloadGroup);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_path:");
v4.append(arg9.iGH);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_child_version:");
v4.append(arg9.iGX.iEx);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_series:");
v4.append(arg9.iGX.iEw);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_arch:");
v4.append(arg9.iGX.iEt);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_vfp3:");
v4.append(arg9.iGX.iEv);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_vfp:");
v4.append(arg9.iGX.iEu);
ArrayList v3_2 = arg9.iGX.iEz;
if(v3_2 != null && v3_2.size() != 0) {
Iterator v3_3 = v3_2.iterator();
while(v3_3.hasNext()) {
Object v4_1 = v3_3.next();
StringBuilder v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_name:");
v5.append(((au)v4_1).getName());
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_ver_name:");
v5.append(((au)v4_1).aDA());
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_ver_code:");
v5.append(((au)v4_1).gBl);
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_req_type:");
v5.append(((au)v4_1).gBq);
}
}
j v3_4 = new j();
m.b(v3_4);
h v4_2 = new h();
m.b(v4_2);
ay v5_1 = new ay();
v3_4.hS("");
v3_4.setImsi("");
v3_4.hV("");
v5_1.bPQ = v3_4;
v5_1.bPP = v4_2;
v5_1.yr(arg9.iGX.ipR);
v5_1.gBF = arg9.iGX.mMode;
v5_1.gBI = arg9.iGX.iEz;
v3_2 = v5_1.gAr;
c.aBh();
v3_2.add(g.fs("os_ver", c.getRomInfo()));
v3_2.add(g.fs("processor_arch", com.uc.b.a.a.c.getCpuArch()));
v3_2.add(g.fs("cpu_arch", com.uc.b.a.a.c.Pb()));
String v4_3 = com.uc.b.a.a.c.Pd();
v3_2.add(g.fs("cpu_vfp", v4_3));
v3_2.add(g.fs("net_type", String.valueOf(com.uc.base.system.a.Jo())));
v3_2.add(g.fs("fromhost", arg9.iGX.iEm));
v3_2.add(g.fs("plugin_ver", arg9.iGX.iEn));
v3_2.add(g.fs("target_lang", arg9.iGX.iEs));
v3_2.add(g.fs("vitamio_cpu_arch", arg9.iGX.iEt));
v3_2.add(g.fs("vitamio_vfp", arg9.iGX.iEu));
v3_2.add(g.fs("vitamio_vfp3", arg9.iGX.iEv));
v3_2.add(g.fs("plugin_child_ver", arg9.iGX.iEx));
v3_2.add(g.fs("ver_series", arg9.iGX.iEw));
v3_2.add(g.fs("child_ver", r.aVw()));
v3_2.add(g.fs("cur_ver_md5", arg9.iGX.iEl));
v3_2.add(g.fs("cur_ver_signature", SystemHelper.getUCMSignature()));
v3_2.add(g.fs("upgrade_log", i.bjt()));
v3_2.add(g.fs("silent_install", String.valueOf(arg9.iGX.iDQ)));
v3_2.add(g.fs("silent_state", String.valueOf(arg9.iGX.iEp)));
v3_2.add(g.fs("silent_file", arg9.iGX.iEq));
v3_2.add(g.fs("silent_type", String.valueOf(arg9.iGX.iEr)));
v3_2.add(g.fs("cpu_archit", com.uc.b.a.a.c.Pc()));
v3_2.add(g.fs("cpu_set", SystemHelper.getCpuInstruction()));
boolean v4_4 = v4_3 == null || !v4_3.contains("neon") ? false : true;
v3_2.add(g.fs("neon", String.valueOf(v4_4)));
v3_2.add(g.fs("cpu_cores", String.valueOf(com.uc.b.a.a.c.Jl())));
v3_2.add(g.fs("ram_1", String.valueOf(com.uc.b.a.a.h.Po())));
v3_2.add(g.fs("totalram", String.valueOf(com.uc.b.a.a.h.OL())));
c.aBh();
v3_2.add(g.fs("rom_1", c.getRomInfo()));
v4_5 = e.getScreenWidth();
int v6 = e.getScreenHeight();
StringBuilder v7 = new StringBuilder();
v7.append(v4_5);
v7.append("*");
v7.append(v6);
v3_2.add(g.fs("ss", v7.toString()));
v3_2.add(g.fs("api_level", String.valueOf(Build$VERSION.SDK_INT)));
v3_2.add(g.fs("uc_apk_list", SystemHelper.getUCMobileApks()));
Iterator v4_6 = arg9.iGX.iEA.entrySet().iterator();
while(v4_6.hasNext()) {
Object v6_1 = v4_6.next();
v3_2.add(g.fs(((Map$Entry)v6_1).getKey(), ((Map$Entry)v6_1).getValue()));
}
v3 = v5_1.toByteArray();
}
if(v3 == null) {
this.iGY.iGI.a(arg9, "up_encode", "yes", "fail");
return;
}
v4_5 = this.iGY.iGw ? 0x1F : 0;
if(v3 == null) {
}
else {
v3 = g.i(v4_5, v3);
if(v3 == null) {
}
else {
v1 = new byte[v3.length + 16];
byte[] v6_2 = new byte[16];
Arrays.fill(v6_2, 0);
v6_2[0] = 0x5F;
v6_2[1] = 0;
v6_2[2] = ((byte)v4_5);
v6_2[3] = -50;
System.arraycopy(v6_2, 0, v1, 0, 16);
System.arraycopy(v3, 0, v1, 16, v3.length);
}
}
if(v1 == null) {
this.iGY.iGI.a(arg9, "up_encrypt", "yes", "fail");
return;
}
if(TextUtils.isEmpty(this.iGY.mUpgradeUrl)) {
this.iGY.iGI.a(arg9, "up_url", "yes", "fail");
return;
}
StringBuilder v0 = new StringBuilder("[");
v0.append(arg9.iGX.ipR);
v0.append("]url:");
v0.append(this.iGY.mUpgradeUrl);
com.uc.browser.core.d.c.i v0_1 = this.iGY.iGI;
v3_1 = this.iGY.mUpgradeUrl;
com.uc.base.net.e v0_2 = new com.uc.base.net.e(new com.uc.browser.core.d.c.i$a(v0_1, arg9));
v3_1 = v3_1.contains("?") ? v3_1 + "&dataver=pb" : v3_1 + "?dataver=pb";
n v3_5 = v0_2.uc(v3_1);
m.b(v3_5, false);
v3_5.setMethod("POST");
v3_5.setBodyProvider(v1);
v0_2.b(v3_5);
this.iGY.iGI.a(arg9, "up_null", "yes", "success");
this.iGY.iGI.b(arg9);
}

Мо дар ин ҷо ташаккули дархости POST-ро мебинем. Мо ба эҷоди массиви 16 байт ва пур кардани он диққат медиҳем: 0x5F, 0, 0x1F, -50 (=0xCE). Бо он чизе ки мо дар дархости боло дидем, мувофиқат мекунад.

Дар ҳамон синф шумо метавонед як синфи лонаеро бинед, ки боз як усули ҷолиб дорад:

        public final void a(l arg10, byte[] arg11) {
f v0 = this.iGQ;
StringBuilder v1 = new StringBuilder("[");
v1.append(arg10.iGX.ipR);
v1.append("]:UpgradeSuccess");
byte[] v1_1 = null;
if(arg11 == null) {
}
else if(arg11.length < 16) {
}
else {
if(arg11[0] != 0x60 && arg11[3] != 0xFFFFFFD0) {
goto label_57;
}
int v3 = 1;
int v5 = arg11[1] == 1 ? 1 : 0;
if(arg11[2] != 1 && arg11[2] != 11) {
if(arg11[2] == 0x1F) {
}
else {
v3 = 0;
}
}
byte[] v7 = new byte[arg11.length - 16];
System.arraycopy(arg11, 16, v7, 0, v7.length);
if(v3 != 0) {
v7 = g.j(arg11[2], v7);
}
if(v7 == null) {
goto label_57;
}
if(v5 != 0) {
v1_1 = g.P(v7);
goto label_57;
}
v1_1 = v7;
}
label_57:
if(v1_1 == null) {
v0.iGY.iGI.a(arg10, "up_decrypt", "yes", "fail");
return;
}
q v11 = g.b(arg10, v1_1);
if(v11 == null) {
v0.iGY.iGI.a(arg10, "up_decode", "yes", "fail");
return;
}
if(v0.iGY.iGt) {
v0.d(arg10);
}
if(v0.iGY.iGo != null) {
v0.iGY.iGo.a(0, ((o)v11));
}
if(v0.iGY.iGs) {
v0.iGY.a(((o)v11));
v0.iGY.iGI.a(v11, "up_silent", "yes", "success");
v0.iGY.iGI.a(v11);
return;
}
v0.iGY.iGI.a(v11, "up_silent", "no", "success");
}
}

Ин усул массиви байтҳоро ҳамчун вуруд мегирад ва месанҷад, ки байти сифр 0x60 ё байти сеюм 0xD0 ва байти дуюм 1, 11 ё 0x1F аст. Мо ба посухи сервер назар мекунем: байти сифр 0x60, дуюм 0x1F, сеюм 0x60. Чунин ба назар мерасад, ки ба мо лозим аст. Аз рӯи сатрҳо («up_decrypt», масалан), бояд дар ин ҷо усуле даъват карда шавад, ки посухи серверро рамзкушоӣ кунад.
Биёед ба усул гузарем gj. Аҳамият диҳед, ки далели аввал байт дар ҷуброни 2 аст (яъне 0x1F дар ҳолати мо) ва дуввум посухи сервер бидуни
16 байти аввал.

     public static byte[] j(int arg1, byte[] arg2) {
if(arg1 == 1) {
arg2 = c.c(arg2, c.adu);
}
else if(arg1 == 11) {
arg2 = m.aF(arg2);
}
else if(arg1 != 0x1F) {
}
else {
arg2 = EncryptHelper.decrypt(arg2);
}
return arg2;
}

Аён аст, ки дар ин ҷо мо алгоритми рамзкушоиро интихоб мекунем ва ҳамон байтеро, ки дар мост
ҳолати баробар ба 0x1F, яке аз се варианти имконпазирро ифода мекунад.

Мо таҳлили кодро идома медиҳем. Пас аз якчанд ҷаҳида мо худро дар як усули бо номи худфаъолкунанда пайдо мекунем decryptBytesByKey.

Дар ин ҷо ду байти дигар аз посухи мо ҷудо мешавад ва аз онҳо сатр ба даст меояд. Маълум аст, ки бо ин роҳ калиди рамзкушоии паём интихоб мешавад.

    private static byte[] decryptBytesByKey(byte[] bytes) {
byte[] v0 = null;
if(bytes != null) {
try {
if(bytes.length < EncryptHelper.PREFIX_BYTES_SIZE) {
}
else if(bytes.length == EncryptHelper.PREFIX_BYTES_SIZE) {
return v0;
}
else {
byte[] prefix = new byte[EncryptHelper.PREFIX_BYTES_SIZE];  // 2 байта
System.arraycopy(bytes, 0, prefix, 0, prefix.length);
String keyId = c.ayR().d(ByteBuffer.wrap(prefix).getShort()); // Выбор ключа
if(keyId == null) {
return v0;
}
else {
a v2 = EncryptHelper.ayL();
if(v2 == null) {
return v0;
}
else {
byte[] enrypted = new byte[bytes.length - EncryptHelper.PREFIX_BYTES_SIZE];
System.arraycopy(bytes, EncryptHelper.PREFIX_BYTES_SIZE, enrypted, 0, enrypted.length);
return v2.l(keyId, enrypted);
}
}
}
}
catch(SecException v7_1) {
EncryptHelper.handleDecryptException(((Throwable)v7_1), v7_1.getErrorCode());
return v0;
}
catch(Throwable v7) {
EncryptHelper.handleDecryptException(v7, 2);
return v0;
}
}
return v0;
}

Ба пеш нигоҳ карда, мо қайд мекунем, ки дар ин марҳила мо ҳоло калидро нагирифтаем, балки танҳо "идентификатор"-и онро мегирем. Гирифтани калид каме мушкилтар аст.

Дар усули навбатӣ ба параметрҳои мавҷуда ду параметри дигар илова карда мешаванд, ки чаҳортои онҳоро ташкил медиҳанд: рақами ҷодугарӣ 16, идентификатори калид, маълумоти рамзгузорӣ ва сатри нофаҳмо (дар ҳолати мо холӣ).

    public final byte[] l(String keyId, byte[] encrypted) throws SecException {
return this.ayJ().staticBinarySafeDecryptNoB64(16, keyId, encrypted, "");
}

Пас аз як қатор гузаришҳо мо ба усул мерасем staticBinarySafeDecryptNoB64 интерфейс com.alibaba.wireless.security.open.staticdataencrypt.IStaticDataEncryptComponent. Дар коди асосии барнома ягон синфе вуҷуд надорад, ки ин интерфейсро амалӣ мекунанд. Дар файл чунин синф мавҷуд аст lib/armeabi-v7a/libsgmain.so, ки дар асл як .so нест, балки як .jar аст. Усуле, ки мо ба он таваҷҷӯҳ дорем, ба таври зерин амалӣ карда мешавад:

package com.alibaba.wireless.security.a.i;
// ...
public class a implements IStaticDataEncryptComponent {
private ISecurityGuardPlugin a;
// ...
private byte[] a(int mode, int magicInt, int xzInt, String keyId, byte[] encrypted, String magicString) {
return this.a.getRouter().doCommand(10601, new Object[]{Integer.valueOf(mode), Integer.valueOf(magicInt), Integer.valueOf(xzInt), keyId, encrypted, magicString});
}
// ...
private byte[] b(int magicInt, String keyId, byte[] encrypted, String magicString) {
return this.a(2, magicInt, 0, keyId, encrypted, magicString);
}
// ...
public byte[] staticBinarySafeDecryptNoB64(int magicInt, String keyId, byte[] encrypted, String magicString) throws SecException {
if(keyId != null && keyId.length() > 0 && magicInt >= 0 && magicInt < 19 && encrypted != null && encrypted.length > 0) {
return this.b(magicInt, keyId, encrypted, magicString);
}
throw new SecException("", 301);
}
//...
}

Дар ин ҷо рӯйхати параметрҳои мо бо ду адади бутуни дигар пурра карда мешаванд: 2 ва 0.
ҳама чиз, 2 маънои рамзкушоӣ, чунон ки дар усули doFinal синфи система javax.crypto.Cipher. Ва ҳамаи ин ба як роутер бо рақами 10601 интиқол дода мешавад - ин аз афташ рақами фармон аст.

Пас аз силсилаи навбатии гузариш мо синферо пайдо мекунем, ки интерфейсро амалӣ мекунад IRouterComponent ва усул doCommand:

package com.alibaba.wireless.security.mainplugin;
import com.alibaba.wireless.security.framework.IRouterComponent;
import com.taobao.wireless.security.adapter.JNICLibrary;
public class a implements IRouterComponent {
public a() {
super();
}
public Object doCommand(int arg2, Object[] arg3) {
return JNICLibrary.doCommandNative(arg2, arg3);
}
}

Ва инчунин синф Китобхонаи JNICL, ки дар он усули ватанй эълон карда шудааст doCommandNative:

package com.taobao.wireless.security.adapter;
public class JNICLibrary {
public static native Object doCommandNative(int arg0, Object[] arg1);
}

Ин маънои онро дорад, ки мо бояд дар коди ватанӣ усул пайдо кунем doCommandNative. Ва дар ин ҷо фароғат оғоз мешавад.

Камбудии рамзи мошин

Дар файл libsgmain.so (ки воқеан як .jar аст ва дар он мо татбиқи баъзе интерфейсҳои марбут ба рамзкунониро дар боло ёфтем) як китобхонаи маҳаллӣ вуҷуд дорад: libsgmainso-6.4.36.so. Мо онро дар IDA мекушоем ва як қатор қуттиҳои муколамаро бо хатогиҳо мегирем. Мушкилот дар он аст, ки ҷадвали сарлавҳаи бахш нодуруст аст. Ин бо мақсади мураккаб кардани таҳлил анҷом дода мешавад.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Аммо ин лозим нест: барои дуруст бор кардани файли ELF ва таҳлили он ҷадвали сарлавҳаи барнома кифоя аст. Аз ин рӯ, мо танҳо ҷадвали бахшро нест карда, майдонҳои мувофиқро дар сарлавҳа сифр мекунем.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Файлро дар IDA боз кушоед.

Ду роҳи гуфтан ба мошини виртуалии Java вуҷуд дорад, ки маҳз дар китобхонаи маҳаллӣ татбиқи усуле, ки дар коди Java ҳамчун модарӣ эълон шудааст, ҷойгир аст. Аввал ин аст, ки ба он номи намуд дода шавад Java_package_name_ClassName_MethodName.

Дуюм ин ба қайд гирифтани он ҳангоми боркунии китобхона (дар функсия JNI_OnLoad)
бо истифода аз занги функсия Бақайдгирии шаҳрвандон.

Дар ҳолати мо, агар мо усули аввалро истифода барем, ном бояд чунин бошад: Java_com_taobao_wireless_security_adapter_JNICLibrary_doCommandNative.

Дар байни функсияҳои содиротӣ чунин функсия вуҷуд надорад, ки маънои онро дорад, ки шумо бояд зангро ҷустуҷӯ кунед Бақайдгирии шаҳрвандон.
Биёед ба функсия равем JNI_OnLoad ва мо ин расмро мебинем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дар ин ҷо чӣ гап? Дар назари аввал, оғоз ва анҷоми функсия барои меъмории ARM хос аст. Дастури аввал дар стек мундариҷаи регистрҳоро, ки функсия ҳангоми кори худ истифода хоҳад кард (дар ин ҳолат R0, R1 ва R2), инчунин мундариҷаи реестри LR, ки суроғаи бозгашти функсияро дар бар мегирад, нигоҳ медорад. . Дастури охирин регистрҳои захирашударо барқарор мекунад ва суроғаи бозгашт фавран дар реестри компютер ҷойгир карда мешавад - ҳамин тавр аз функсия бармегардад. Аммо агар шумо бодиққат назар кунед, шумо хоҳед дид, ки дастури охирин суроғаи бозгашти дар стек захирашударо тағир медиҳад. Биёед ҳисоб кунем, ки пас аз он чӣ гуна хоҳад буд
иҷрои код. Суроғаи муайяни 1xB0 ба R130 бор карда мешавад, аз он 5 тарҳ карда мешавад, сипас ба R0 интиқол дода мешавад ва ба он 0x10 илова карда мешавад. Маълум мешавад, ки 0xB13B. Ҳамин тариқ, IDA чунин мешуморад, ки дастури охирин бозгашти функсияи муқаррарӣ аст, аммо дар асл он ба суроғаи ҳисобшудаи 0xB13B меравад.

Дар ин ҷо хотиррасон кардан лозим аст, ки протсессорҳои ARM дорои ду режим ва ду маҷмӯи дастурҳо мебошанд: ARM ва Thumb. Андозаи камтарин бит ба протсессор мегӯяд, ки кадом маҷмӯи дастурҳо истифода мешавад. Ин аст, ки суроға воқеан 0xB13A аст ва яке аз каме камтарин ҳолати ангуштро нишон медиҳад.

Ба оғози ҳар як функсия дар ин китобхона як "адаптер"-и шабеҳ илова карда шудааст ва
рамзи ахлот. Мо минбаъд дар бораи онҳо муфассал сухан намегӯем - мо танҳо дар хотир дорем
ки ибтидои хакикии кариб хамаи вазифахо андаке дуртар аст.

Азбаски рамз ба таври возеҳ ба 0xB13A намегузарад, худи IDA эътироф накард, ки код дар ин макон ҷойгир аст. Бо ҳамин сабаб, он аксари кодҳои китобхонаро ҳамчун код эътироф намекунад, ки таҳлилро то андозае мушкил мекунад. Мо ба IDA мегӯем, ки ин рамз аст ва ин ҳодиса рӯй медиҳад:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ҷадвал ба таври равшан аз 0xB144 оғоз меёбад. Дар sub_494C чист?

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ҳангоми даъват кардани ин функсия дар реестри LR, мо суроғаи ҷадвали қаблан зикршударо мегирем (0xB144). Дар R0 - индекс дар ин ҷадвал. Яъне, арзиш аз ҷадвал гирифта, ба LR илова карда мешавад ва натиҷа аст
суроғаи рафтан. Биёед кӯшиш кунем, ки онро ҳисоб кунем: 0xB144 + [0xB144 + 8* 4] = 0xB144 + 0x120 = 0xB264. Мо ба суроғаи гирифташуда меравем ва аслан якчанд дастурҳои муфидро мебинем ва боз ба 0xB140 меравем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Акнун гузариш дар ҷуброн бо индекси 0x20 аз ҷадвал ба амал меояд.

Аз рӯи андозаи ҷадвал, дар код чунин гузаришҳо зиёд хоҳанд буд. Саволе ба миён меояд, ки оё бо ин корро ба таври автоматӣ бидуни ҳисоб кардани суроғаҳо дастӣ кардан мумкин аст? Ва скриптҳо ва қобилияти пач кардани код дар IDA ба кӯмаки мо меоянд:

def put_unconditional_branch(source, destination):
offset = (destination - source - 4) >> 1
if offset > 2097151 or offset < -2097152:
raise RuntimeError("Invalid offset")
if offset > 1023 or offset < -1024:
instruction1 = 0xf000 | ((offset >> 11) & 0x7ff)
instruction2 = 0xb800 | (offset & 0x7ff)
patch_word(source, instruction1)
patch_word(source + 2, instruction2)
else:
instruction = 0xe000 | (offset & 0x7ff)
patch_word(source, instruction)
ea = here()
if get_wide_word(ea) == 0xb503: #PUSH {R0,R1,LR}
ea1 = ea + 2
if get_wide_word(ea1) == 0xbf00: #NOP
ea1 += 2
if get_operand_type(ea1, 0) == 1 and get_operand_value(ea1, 0) == 0 and get_operand_type(ea1, 1) == 2:
index = get_wide_dword(get_operand_value(ea1, 1))
print "index =", hex(index)
ea1 += 2
if get_operand_type(ea1, 0) == 7:
table = get_operand_value(ea1, 0) + 4
elif get_operand_type(ea1, 1) == 2:
table = get_operand_value(ea1, 1) + 4
else:
print "Wrong operand type on", hex(ea1), "-", get_operand_type(ea1, 0), get_operand_type(ea1, 1)
table = None
if table is None:
print "Unable to find table"
else:
print "table =", hex(table)
offset = get_wide_dword(table + (index << 2))
put_unconditional_branch(ea, table + offset)
else:
print "Unknown code", get_operand_type(ea1, 0), get_operand_value(ea1, 0), get_operand_type(ea1, 1) == 2
else:
print "Unable to detect first instruction"

Курсорро дар хати 0xB26A ҷойгир кунед, скриптро иҷро кунед ва гузаришро ба 0xB4B0 бубинед:

Ҷустуҷӯи осебпазирӣ дар Browser UC

IDA боз ин минтақаро ҳамчун код эътироф накард. Мо ба ӯ кӯмак мекунем ва дар он ҷо тарҳи дигареро мебинем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дастурҳо пас аз BLX ба назар чандон маъно надоранд, он бештар ба як навъ ҷойивазкунӣ монанд аст. Биёед sub_4964-ро бубинем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ва дар ҳақиқат, дар ин ҷо як калима дар суроғае, ки дар LR ҷойгир аст, гирифта мешавад ва ба ин суроға илова карда мешавад, ки пас аз он арзиши суроғаи натиҷавӣ гирифта мешавад ва ба стек гузошта мешавад. Инчунин, 4 ба LR илова карда мешавад, то пас аз баргаштан аз функсия, ин ҳамон ҷуброн гузаронида шавад. Пас аз он фармони POP {R1} арзиши натиҷаро аз стек мегирад. Агар шумо ба он чизе, ки дар суроғаи 0xB4BA + 0xEA = 0xB5A4 ҷойгир аст, назар кунед, шумо чизеро ба ҷадвали суроғаҳо монанд хоҳед дид:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Барои ислоҳ кардани ин тарҳ ба шумо лозим меояд, ки аз код ду параметр гиред: офсет ва рақами реестр, ки дар он шумо натиҷаро гузоштан мехоҳед. Барои ҳар як феҳристи имконпазир шумо бояд як пораи кодро пешакӣ омода кунед.

patches = {}
patches[0] = (0x00, 0xbf, 0x01, 0x48, 0x00, 0x68, 0x02, 0xe0)
patches[1] = (0x00, 0xbf, 0x01, 0x49, 0x09, 0x68, 0x02, 0xe0)
patches[2] = (0x00, 0xbf, 0x01, 0x4a, 0x12, 0x68, 0x02, 0xe0)
patches[3] = (0x00, 0xbf, 0x01, 0x4b, 0x1b, 0x68, 0x02, 0xe0)
patches[4] = (0x00, 0xbf, 0x01, 0x4c, 0x24, 0x68, 0x02, 0xe0)
patches[5] = (0x00, 0xbf, 0x01, 0x4d, 0x2d, 0x68, 0x02, 0xe0)
patches[8] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0x80, 0xd8, 0xf8, 0x00, 0x80, 0x01, 0xe0)
patches[9] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0x90, 0xd9, 0xf8, 0x00, 0x90, 0x01, 0xe0)
patches[10] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0xa0, 0xda, 0xf8, 0x00, 0xa0, 0x01, 0xe0)
patches[11] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0xb0, 0xdb, 0xf8, 0x00, 0xb0, 0x01, 0xe0)
ea = here()
if (get_wide_word(ea) == 0xb082 #SUB SP, SP, #8
and get_wide_word(ea + 2) == 0xb503): #PUSH {R0,R1,LR}
if get_operand_type(ea + 4, 0) == 7:
pop = get_bytes(ea + 12, 4, 0)
if pop[1] == 'xbc':
register = -1
r = get_wide_byte(ea + 12)
for i in range(8):
if r == (1 << i):
register = i
break
if register == -1:
print "Unable to detect register"
else:
address = get_wide_dword(ea + 8) + ea + 8
for b in patches[register]:
patch_byte(ea, b)
ea += 1
if ea % 4 != 0:
ea += 2
patch_dword(ea, address)
elif pop[:3] == 'x5dxf8x04':
register = ord(pop[3]) >> 4
if register in patches:
address = get_wide_dword(ea + 8) + ea + 8
for b in patches[register]:
patch_byte(ea, b)
ea += 1
patch_dword(ea, address)
else:
print "POP instruction not found"
else:
print "Wrong operand type on +4:", get_operand_type(ea + 4, 0)
else:
print "Unable to detect first instructions"

Мо курсорро дар аввали сохторе, ки мехоҳем иваз кунем - 0xB4B2 - ҷойгир мекунем ва скриптро иҷро мекунем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Илова ба сохторҳои қаблан зикршуда, код инчунин дорои инҳост:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Тавре ки дар ҳолати қаблӣ, пас аз дастури BLX ҷуброн вуҷуд дорад:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Мо офсетро ба суроғаи LR мегирем, онро ба LR илова мекунем ва ба он ҷо меравем. 0x72044 + 0xC = 0x72050. Скрипти ин тарҳ хеле содда аст:

def put_unconditional_branch(source, destination):
offset = (destination - source - 4) >> 1
if offset > 2097151 or offset < -2097152:
raise RuntimeError("Invalid offset")
if offset > 1023 or offset < -1024:
instruction1 = 0xf000 | ((offset >> 11) & 0x7ff)
instruction2 = 0xb800 | (offset & 0x7ff)
patch_word(source, instruction1)
patch_word(source + 2, instruction2)
else:
instruction = 0xe000 | (offset & 0x7ff)
patch_word(source, instruction)
ea = here()
if get_wide_word(ea) == 0xb503: #PUSH {R0,R1,LR}
ea1 = ea + 6
if get_wide_word(ea + 2) == 0xbf00: #NOP
ea1 += 2
offset = get_wide_dword(ea1)
put_unconditional_branch(ea, (ea1 + offset) & 0xffffffff)
else:
print "Unable to detect first instruction"

Натиҷаи иҷрои скрипт:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Пас аз он ки ҳама чиз дар функсия часпонида мешавад, шумо метавонед IDA-ро ба оғози воқеии он ишора кунед. Он тамоми рамзи функсияро ҷамъ мекунад ва онро бо истифода аз HexRays декомпиляция кардан мумкин аст.

Рамзгузории сатрҳо

Мо дар китобхона мубориза бурдан бо печидаи коди мошинро ёд гирифтем libsgmainso-6.4.36.so аз Browser UC ва рамзи функсияро гирифт JNI_OnLoad.

int __fastcall real_JNI_OnLoad(JavaVM *vm)
{
int result; // r0
jclass clazz; // r0 MAPDST
int v4; // r0
JNIEnv *env; // r4
int v6; // [sp-40h] [bp-5Ch]
int v7; // [sp+Ch] [bp-10h]
v7 = *(_DWORD *)off_8AC00;
if ( !vm )
goto LABEL_39;
sub_7C4F4();
env = (JNIEnv *)sub_7C5B0(0);
if ( !env )
goto LABEL_39;
v4 = sub_72CCC();
sub_73634(v4);
sub_73E24(&unk_83EA6, &v6, 49);
clazz = (jclass)((int (__fastcall *)(JNIEnv *, int *))(*env)->FindClass)(env, &v6);
if ( clazz
&& (sub_9EE4(),
sub_71D68(env),
sub_E7DC(env) >= 0
&& sub_69D68(env) >= 0
&& sub_197B4(env, clazz) >= 0
&& sub_E240(env, clazz) >= 0
&& sub_B8B0(env, clazz) >= 0
&& sub_5F0F4(env, clazz) >= 0
&& sub_70640(env, clazz) >= 0
&& sub_11F3C(env) >= 0
&& sub_21C3C(env, clazz) >= 0
&& sub_2148C(env, clazz) >= 0
&& sub_210E0(env, clazz) >= 0
&& sub_41B58(env, clazz) >= 0
&& sub_27920(env, clazz) >= 0
&& sub_293E8(env, clazz) >= 0
&& sub_208F4(env, clazz) >= 0) )
{
result = (sub_B7B0(env, clazz) >> 31) | 0x10004;
}
else
{
LABEL_39:
result = -1;
}
return result;
}

Биёед ба сатрҳои зерин наздиктар назар андозем:

  sub_73E24(&unk_83EA6, &v6, 49);
clazz = (jclass)((int (__fastcall *)(JNIEnv *, int *))(*env)->FindClass)(env, &v6);

Дар функсия sub_73E24 номи синф ба таври равшан рамзкушоӣ карда мешавад. Ҳамчун параметрҳо ба ин функсия, нишондиҳанда ба додаҳои шабеҳи маълумоти рамзшуда, буфери муайян ва рақам интиқол дода мешавад. Аён аст, ки пас аз даъват кардани функсия, дар буфер хати рамзкушошуда пайдо мешавад, зеро он ба функсия интиқол дода мешавад. FindClass, ки номи синфро ҳамчун параметри дуюм мегирад. Аз ин рӯ, адад андозаи буфер ё дарозии сатр аст. Биёед кӯшиш кунем, ки номи синфро фаҳмем, он бояд ба мо бигӯяд, ки оё мо дар самти дуруст меравем. Биёед муфассалтар бубинем, ки дар он чӣ рӯй медиҳад sub_73E24.

int __fastcall sub_73E56(unsigned __int8 *in, unsigned __int8 *out, size_t size)
{
int v4; // r6
int v7; // r11
int v8; // r9
int v9; // r4
size_t v10; // r5
int v11; // r0
struc_1 v13; // [sp+0h] [bp-30h]
int v14; // [sp+1Ch] [bp-14h]
int v15; // [sp+20h] [bp-10h]
v4 = 0;
v15 = *(_DWORD *)off_8AC00;
v14 = 0;
v7 = sub_7AF78(17);
v8 = sub_7AF78(size);
if ( !v7 )
{
v9 = 0;
goto LABEL_12;
}
(*(void (__fastcall **)(int, const char *, int))(v7 + 12))(v7, "DcO/lcK+h?m3c*q@", 16);
if ( !v8 )
{
LABEL_9:
v4 = 0;
goto LABEL_10;
}
v4 = 0;
if ( !in )
{
LABEL_10:
v9 = 0;
goto LABEL_11;
}
v9 = 0;
if ( out )
{
memset(out, 0, size);
v10 = size - 1;
(*(void (__fastcall **)(int, unsigned __int8 *, size_t))(v8 + 12))(v8, in, v10);
memset(&v13, 0, 0x14u);
v13.field_4 = 3;
v13.field_10 = v7;
v13.field_14 = v8;
v11 = sub_6115C(&v13, &v14);
v9 = v11;
if ( v11 )
{
if ( *(_DWORD *)(v11 + 4) == v10 )
{
qmemcpy(out, *(const void **)v11, v10);
v4 = *(_DWORD *)(v9 + 4);
}
else
{
v4 = 0;
}
goto LABEL_11;
}
goto LABEL_9;
}
LABEL_11:
sub_7B148(v7);
LABEL_12:
if ( v8 )
sub_7B148(v8);
if ( v9 )
sub_7B148(v9);
return v4;
}

функсия sub_7AF78 як мисоли контейнерро барои массивҳои байтҳои андозаи муайяншуда эҷод мекунад (мо ба таври муфассал дар бораи ин контейнерҳо таваққуф намекунем). Дар ин ҷо ду чунин контейнер сохта шудаанд: яке аз он сатр иборат аст "DcO/lcK+h?m3c*q@" (фаҳмидани он осон аст, ки ин калид аст), дигаре дорои маълумоти рамзгузоришуда мебошад. Баъдан, ҳарду объект дар сохтори муайян ҷойгир карда мешаванд, ки ба функсия интиқол дода мешаванд sub_6115C. Биёед инчунин майдони дорои арзиши 3-ро дар ин сохтор қайд кунем. Биёед бубинем, ки минбаъд бо ин сохтор чӣ мешавад.

int __fastcall sub_611B4(struc_1 *a1, _DWORD *a2)
{
int v3; // lr
unsigned int v4; // r1
int v5; // r0
int v6; // r1
int result; // r0
int v8; // r0
*a2 = 820000;
if ( a1 )
{
v3 = a1->field_14;
if ( v3 )
{
v4 = a1->field_4;
if ( v4 < 0x19 )
{
switch ( v4 )
{
case 0u:
v8 = sub_6419C(a1->field_0, a1->field_10, v3);
goto LABEL_17;
case 3u:
v8 = sub_6364C(a1->field_0, a1->field_10, v3);
goto LABEL_17;
case 0x10u:
case 0x11u:
case 0x12u:
v8 = sub_612F4(
a1->field_0,
v4,
*(_QWORD *)&a1->field_8,
*(_QWORD *)&a1->field_8 >> 32,
a1->field_10,
v3,
a2);
goto LABEL_17;
case 0x14u:
v8 = sub_63A28(a1->field_0, v3);
goto LABEL_17;
case 0x15u:
sub_61A60(a1->field_0, v3, a2);
return result;
case 0x16u:
v8 = sub_62440(a1->field_14);
goto LABEL_17;
case 0x17u:
v8 = sub_6226C(a1->field_10, v3);
goto LABEL_17;
case 0x18u:
v8 = sub_63530(a1->field_14);
LABEL_17:
v6 = 0;
if ( v8 )
{
*a2 = 0;
v6 = v8;
}
return v6;
default:
LOWORD(v5) = 28032;
goto LABEL_5;
}
}
}
}
LOWORD(v5) = -27504;
LABEL_5:
HIWORD(v5) = 13;
v6 = 0;
*a2 = v5;
return v6;
}

Параметри гузариш майдони сохторест, ки қаблан арзиши 3 таъин шуда буд. Ба ҳолати 3 нигаред: ба функсия sub_6364C параметрҳо аз сохторе, ки дар он ҷо дар вазифаи қаблӣ илова карда шудаанд, интиқол дода мешаванд, яъне калид ва маълумоти рамзшуда. Агар бодиккат назар кунед sub_6364C, шумо метавонед алгоритми RC4-ро дар он эътироф кунед.

Мо як алгоритм ва калид дорем. Биёед кӯшиш кунем, ки номи синфро фаҳмем. Ин аст он чизе ки рӯй дод: com/taobao/wireless/security/adapter/JNICLibrary. Аҷоиб! Мо дар роҳи дуруст ҳастем.

Дарахти фармон

Ҳоло ба мо лозим аст, ки як мушкилот пайдо кунем Бақайдгирии шаҳрвандон, ки моро ба функсия ишора мекунад doCommandNative. Биёед ба функсияҳое, ки аз он даъват шудаанд, дида бароем JNI_OnLoad, ва мо онро дар sub_B7B0:

int __fastcall sub_B7F6(JNIEnv *env, jclass clazz)
{
char signature[41]; // [sp+7h] [bp-55h]
char name[16]; // [sp+30h] [bp-2Ch]
JNINativeMethod method; // [sp+40h] [bp-1Ch]
int v8; // [sp+4Ch] [bp-10h]
v8 = *(_DWORD *)off_8AC00;
decryptString((unsigned __int8 *)&unk_83ED9, (unsigned __int8 *)name, 0x10u);// doCommandNative
decryptString((unsigned __int8 *)&unk_83EEA, (unsigned __int8 *)signature, 0x29u);// (I[Ljava/lang/Object;)Ljava/lang/Object;
method.name = name;
method.signature = signature;
method.fnPtr = sub_B69C;
return ((int (__fastcall *)(JNIEnv *, jclass, JNINativeMethod *, int))(*env)->RegisterNatives)(env, clazz, &method, 1) >> 31;
}

Ва дар ҳақиқат, як усули ватанӣ бо ном дар ин ҷо ба қайд гирифта шудааст doCommandNative. Акнун мо адреси уро медонем. Биёед бубинем, ки ӯ чӣ кор мекунад.

int __fastcall doCommandNative(JNIEnv *env, jobject obj, int command, jarray args)
{
int v5; // r5
struc_2 *a5; // r6
int v9; // r1
int v11; // [sp+Ch] [bp-14h]
int v12; // [sp+10h] [bp-10h]
v5 = 0;
v12 = *(_DWORD *)off_8AC00;
v11 = 0;
a5 = (struc_2 *)malloc(0x14u);
if ( a5 )
{
a5->field_0 = 0;
a5->field_4 = 0;
a5->field_8 = 0;
a5->field_C = 0;
v9 = command % 10000 / 100;
a5->field_0 = command / 10000;
a5->field_4 = v9;
a5->field_8 = command % 100;
a5->field_C = env;
a5->field_10 = args;
v5 = sub_9D60(command / 10000, v9, command % 100, 1, (int)a5, &v11);
}
free(a5);
if ( !v5 && v11 )
sub_7CF34(env, v11, &byte_83ED7);
return v5;
}

Бо ном шумо метавонед тахмин кунед, ки дар ин ҷо нуқтаи вуруди ҳамаи функсияҳост, ки таҳиягарон тасмим гирифтанд, ки ба китобхонаи ватанӣ интиқол диҳанд. Мо ба функсияи рақами 10601 таваҷҷӯҳ дорем.

Шумо метавонед аз код дидан кунед, ки рақами фармон се рақамро тавлид мекунад: фармон / 10000, фармон % 10000 / 100 и фармон % 10, яъне дар ҳолати мо, 1, 6 ва 1. Ин се адад, инчунин нишондиҳанда барои JNIEnv ва аргументҳои ба функсия додашуда ба сохтор илова карда мешаванд ва ба он интиқол дода мешаванд. Бо истифода аз се адади бадастомада (биёед онҳоро N1, N2 ва N3 ишора кунем) дарахти фармонҳо сохта мешавад.

Чизе монанди ин:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дарахт ба таври динамикӣ пур карда мешавад JNI_OnLoad.
Се рақам роҳро дар дарахт рамзгузорӣ мекунад. Ҳар як барги дарахт суроғаи даридаи функсияи мувофиқро дар бар мегирад. Калид дар гиреҳи волидайн аст. Ҷустуҷӯи ҷой дар код, ки функсияи ба мо лозим аст, ба дарахт илова карда мешавад, душвор нест, агар шумо ҳамаи сохторҳои истифодашударо фаҳмед (мо онҳоро тавсиф намекунем, то мақолаи хеле калонро варам накунед).

Мушкилоти бештар

Мо суроғаи функсияеро гирифтем, ки бояд трафикро рамзкушоӣ кунад: 0x5F1AC. Аммо хурсанд шудан барвақт аст: таҳиягарони UC Browser барои мо сюрпризи дигар омода карданд.

Пас аз гирифтани параметрҳо аз массив, ки дар коди Java ташаккул ёфтааст, мо мегирем
ба функсия дар суроғаи 0x4D070. Ва дар ин ҷо моро боз як намуди рамзгузории рамз интизор аст.

Мо ду индексро дар R7 ва R4 гузоштем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Мо индекси аввалро ба R11 мегузорем:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Барои гирифтани суроға аз ҷадвал, индексро истифода баред:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Пас аз рафтан ба суроғаи аввал, индекси дуюм истифода мешавад, ки дар R4 аст. Дар ҷадвал 230 элемент мавҷуд аст.

Дар ин бора чӣ бояд кард? Шумо метавонед ба IDA бигӯед, ки ин коммутатор аст: Таҳрир -> Дигар -> Идиоми гузаришро муайян кунед.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Рамзи натиҷа даҳшатнок аст. Аммо, ҳангоми гузаштан аз ҷангали он, шумо метавонед зангро ба функсияе, ки ба мо аллакай шинос аст, мушоҳида кунед sub_6115C:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Гузариш мавҷуд буд, ки дар ҳолати 3 рамзкушоӣ бо истифода аз алгоритми RC4 мавҷуд буд. Ва дар ин ҳолат сохторе, ки ба функсия дода шудааст, аз параметрҳои ба он додашуда пур карда мешавад doCommandNative. Биёед дар хотир дорем, ки дар он ҷо чӣ доштем magicInt бо арзиши 16. Мо ба ҳолати мувофиқ назар мекунем - ва пас аз якчанд гузариш мо кодеро пайдо мекунем, ки алгоритмро муайян кардан мумкин аст.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Ин AES аст!

Алгоритм вуҷуд дорад, танҳо гирифтани параметрҳои он боқӣ мемонад: режим, калид ва эҳтимолан вектори оғозёбӣ (ҳузури он аз ҳолати кори алгоритми AES вобаста аст). Сохтор бо онҳо бояд дар ҷое пеш аз даъвати функсия ташкил карда шавад sub_6115C, аммо ин қисми рамз махсусан хуб печида аст, бинобар ин идеяи часонидани код ба миён меояд, то ки ҳамаи параметрҳои функсияи рамзкушоӣ ба файл партофта шаванд.

Патч

Барои ба таври дастӣ нанавиштани ҳамаи кодҳои патч бо забони ассемблер, шумо метавонед Android Studio-ро оғоз кунед, дар он ҷо функсияеро нависед, ки ҳамон параметрҳои вурудро ҳамчун функсияи рамзкушоии мо қабул мекунад ва ба файл менависад ва пас кодро нусхабардорӣ кунед, ки компилятор хоҳад кард. тавлид.

Дӯстони мо аз дастаи UC Browser инчунин дар бораи роҳати илова кардани код ғамхорӣ карданд. Биёед дар хотир дорем, ки дар оғози ҳар як функсия мо рамзи партов дорем, ки онро ба осонӣ бо ягон чизи дигар иваз кардан мумкин аст. Хеле қулай 🙂 Аммо, дар оғози функсияи мақсаднок барои код, ки ҳамаи параметрҳоро дар файл захира мекунад, фазои кофӣ нест. Ман маҷбур будам, ки онро ба қисмҳо тақсим кунам ва блокҳои партовҳоро аз вазифаҳои ҳамсоя истифода барам. Дар маҷмӯъ чор қисм буд.

Қисми аввал:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дар меъмории ARM чор параметри аввалини функсия тавассути регистрҳои R0-R3, боқимонда, агар мавҷуд бошад, аз стек гузаронида мешаванд. Феҳристи LR суроғаи бозгаштро дорад. Ҳамаи ин бояд захира карда шавад, то ки функсия пас аз партофтани параметрҳои он кор кунад. Мо инчунин бояд ҳамаи регистрҳоро захира кунем, ки дар ин раванд истифода хоҳем кард, аз ин рӯ мо PUSH.W {R0-R10,LR} -ро иҷро мекунем. Дар R7 мо суроғаи рӯйхати параметрҳоеро мегирем, ки тавассути стек ба функсия интиқол дода мешавад.

Истифодаи функсия фопен биёед файлро кушоем /data/local/tmp/aes дар ҳолати "ab"
яъне барои илова. Дар R0 мо суроғаи номи файлро, дар R1 - суроғаи сатри нишон додани режимро бор мекунем. Ва дар ин ҷо рамзи партов ба охир мерасад, бинобар ин мо ба вазифаи навбатӣ мегузарем. Барои он ки он корашро идома диҳад, мо дар ибтидо гузаришро ба рамзи воқеии функсия гузошта, партовро гузар карда, ба ҷои ахлот идомаи патчро илова мекунем.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Занг задан фопен.

Се параметри аввали функсия aes намуд доранд Int. Азбаски мо дар аввал регистрҳоро дар стек захира кардем, мо метавонем танҳо функсияро гузаронем навиштан суроғаҳои онҳо дар стек.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дар оянда мо се сохтор дорем, ки дорои андозаи маълумот ва нишондиҳандаи маълумот барои калид, вектори оғозёбӣ ва маълумоти рамзгузоришуда мебошанд.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Дар охир, файлро пӯшед, регистрҳоро барқарор кунед ва назоратро ба функсияи воқеӣ интиқол диҳед aes.

Мо APK-ро бо китобхонаи часпак ҷамъоварӣ мекунем, онро имзо мекунем, ба дастгоҳ/эмулятор бор мекунем ва онро оғоз мекунем. Мо мебинем, ки партовгоҳи мо сохта мешавад ва дар онҷо маълумоти зиёде навишта мешавад. Браузер рамзкунониро на танҳо барои трафик истифода мебарад ва тамоми рамзгузорӣ тавассути функсияи мавриди назар мегузарад. Аммо бо баъзе сабабҳо маълумоти зарурӣ вуҷуд надорад ва дархости зарурӣ дар трафик дида намешавад. Барои он ки UC Browser дархости заруриро иҷро накунад, интизор нашавед, биёед аз сервери қаблан гирифташуда ҷавоби рамзшударо гирем ва барномаро дубора часпонед: рамзкушоиро ба onCreate фаъолияти асосӣ илова кунед.

    const/16 v1, 0x62
new-array v1, v1, [B
fill-array-data v1, :encrypted_data
const/16 v0, 0x1f
invoke-static {v0, v1}, Lcom/uc/browser/core/d/c/g;->j(I[B)[B
move-result-object v1
array-length v2, v1
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v2
const-string v0, "ololo"
invoke-static {v0, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

Мо ҷамъ мекунем, имзо мекунем, насб мекунем, ба кор меандозем. Мо NullPointerException мегирем, зеро усул нул баргашт.

Ҳангоми таҳлили минбаъдаи код, функсияе кашф карда шуд, ки сатрҳои ҷолибро шифр мекунад: "META-INF/" ва ".RSA". Чунин ба назар мерасад, ки барнома сертификати худро тасдиқ мекунад. Ё ҳатто калидҳоро аз он тавлид мекунад. Ман аслан намехоҳам бо он чизе ки бо шаҳодатнома рӯй медиҳад, сарукор дошта бошам, аз ин рӯ мо танҳо ба он шаҳодатномаи дуруст медиҳем. Биёед хати рамзшударо часпонем, то ба ҷои "META-INF/" мо "BLABLINF/" гирем, дар APK папкаеро бо ин ном эҷод кунем ва дар он ҷо шаҳодатномаи браузери squirrel илова кунем.

Мо ҷамъ мекунем, имзо мекунем, насб мекунем, ба кор меандозем. Бинго! Мо калид дорем!

MitM

Мо калид ва вектори оғозёбиро ба калид баробар гирифтем. Биёед кӯшиш кунем, ки ҷавоби серверро дар реҷаи CBC рамзкушо кунем.

Ҷустуҷӯи осебпазирӣ дар Browser UC

Мо URL-и бойгониро мебинем, чизе монанд ба MD5, "extract_unzipsize" ва рақам. Мо тафтиш мекунем: MD5-и бойгонӣ якхела аст, андозаи китобхонаи кушодашуда яксон аст. Мо кӯшиш карда истодаем, ки ин китобхонаро часпонед ва онро ба браузер диҳем. Барои нишон додани он, ки китобхонаи часпонидашудаи мо бор карда шудааст, мо нияти сохтани SMS-ро бо матни "PWNED!" оғоз мекунем. Мо ду ҷавобро аз сервер иваз мекунем: puds.ucweb.com/upgrade/index.xhtml ва барои зеркашӣ кардани архив. Дар аввал мо MD5-ро иваз мекунем (андоза пас аз кушодан тағир намеёбад), дар дуюм мо архивро бо китобхонаи часпак дода медиҳем.

Браузер кӯшиш мекунад, ки архивро якчанд маротиба зеркашӣ кунад, пас аз он хатогӣ медиҳад. Аз афташ чизе
ба ӯ маъқул нест. Дар натиҷаи таҳлили ин формати норавшан маълум шуд, ки сервер инчунин андозаи архивро интиқол медиҳад:

Ҷустуҷӯи осебпазирӣ дар Browser UC

Он дар LEB128 рамзгузорӣ шудааст. Пас аз пач, андозаи бойгонӣ бо китобхона каме тағйир ёфт, аз ин рӯ браузер чунин мешуморад, ки бойгонӣ каҷ карда шудааст ва пас аз якчанд кӯшишҳо хатогӣ содир кард.

Андозаи архивро дуруст мекунем... Ва — галаба! 🙂 Натиҷа дар видео аст.

https://www.youtube.com/watch?v=Nfns7uH03J8

Оқибатҳо ва аксуламали таҳиякунанда

Ба ҳамин тариқ, ҳакерҳо метавонанд хусусияти бехатарии UC Browser-ро барои паҳн ва идора кардани китобхонаҳои зараровар истифода баранд. Ин китобхонаҳо дар контексти браузер кор хоҳанд кард, аз ин рӯ онҳо тамоми иҷозатҳои системаи онро мегиранд. Дар натиҷа, имкони намоиш додани равзанаҳои фишинг, инчунин дастрасӣ ба файлҳои кории сукути чинии норанҷӣ, аз ҷумла логинҳо, паролҳо ва кукиҳои дар пойгоҳи додаҳо нигоҳ дошташуда.

Мо бо таҳиягарони UC Browser тамос гирифтем ва онҳоро дар бораи мушкилоте, ки ёфтаем, огоҳ кардем, кӯшиш кардем, ки осебпазирӣ ва хатари онро нишон диҳем, аммо онҳо бо мо чизе нагуфтанд. Дар ҳамин ҳол, браузер нишон додани хусусияти хатарноки худро дар назари оддӣ идома дод. Аммо вақте ки мо ҷузъиёти осебпазириро ошкор кардем, дигар ба мисли пештара нодида гирифтан ғайриимкон буд. 27 март буд
версияи нави UC Browser 12.10.9.1193 бароварда шуд, ки ба сервер тавассути HTTPS дастрасӣ пайдо кард: puds.ucweb.com/upgrade/index.xhtml.

Илова бар ин, пас аз "ислоҳ" ва то замони навиштани ин мақола, кӯшиши кушодани PDF дар браузер боиси паёми хато бо матни "Оҳ, чизе хато шуд!" Ҳангоми кӯшиши кушодани PDF дархост ба сервер дода нашуд, аммо ҳангоми ба кор андохтани браузер дархост дода шуд, ки ба қобилияти идомаи зеркашии коди иҷрошаванда бар хилофи қоидаҳои Google Play ишора мекунад.

Манбаъ: will.com

Илова Эзоҳ