Pagpangita alang sa mga kahuyangan sa UC Browser

Pagpangita alang sa mga kahuyangan sa UC Browser

Pasiuna

Sa katapusan sa Marso kita gitaho, nga ilang nadiskobrehan ang usa ka tinago nga abilidad sa pag-load ug pagpadagan sa unverified code sa UC Browser. Karon atong tan-awon sa detalye kung giunsa kini nga pag-download ug kung giunsa kini magamit sa mga hacker alang sa ilang kaugalingon nga katuyoan.

Kaniadto, ang UC Browser gi-anunsyo ug agresibo kaayo nga giapod-apod: gi-install kini sa mga aparato sa mga tiggamit gamit ang malware, giapod-apod gikan sa lainlaing mga site sa ilawom sa mga file sa video (ie, ang mga tiggamit naghunahuna nga nag-download sila, pananglitan, usa ka porno nga video, apan nakadawat hinuon og APK uban niini nga browser), migamit ug makahahadlok nga mga bandera nga adunay mga mensahe nga ang browser karaan na, huyang, ug uban pa. Sa opisyal nga grupo sa UC Browser sa VK adunay tema, diin ang mga tiggamit makareklamo bahin sa dili patas nga advertising, adunay daghang mga pananglitan didto. Sa 2016 adunay bisan video advertising sa Russian (oo, advertising alang sa usa ka ad-blocking browser).

Sa panahon sa pagsulat, ang UC Browser adunay sobra sa 500 nga mga pag-install sa Google Play. Makapahingangha kini - ang Google Chrome ra ang adunay daghan pa. Lakip sa mga pagrepaso makita nimo ang daghang mga reklamo bahin sa advertising ug pag-redirect sa pipila nga mga aplikasyon sa Google Play. Kini ang hinungdan sa among panukiduki: nakahukom kami nga tan-awon kung ang UC Browser adunay daotan nga gibuhat. Ug kini nahimo nga iyang gibuhat!

Sa code sa aplikasyon, nadiskubre ang abilidad sa pag-download ug pagpadagan sa executable code, nga supak sa mga lagda sa pagmantala sa mga aplikasyon sa Google Play. Agi og dugang sa pag-download sa executable code, ang UC Browser naghimo niini sa dili kasegurohan nga paagi, nga magamit sa paglunsad og usa ka pag-atake sa MitM. Tan-awon nato kon mahimo ba nato ang maong pag-atake.

Ang tanan nga nasulat sa ubos may kalabotan sa bersyon sa UC Browser nga magamit sa Google Play sa panahon sa pagtuon:

package: com.UCMobile.intl
versionName: 12.10.8.1172
versionCode: 10598
sha1 APK-Ρ„Π°ΠΉΠ»Π°: f5edb2243413c777172f6362876041eb0c3a928c

Vektor sa pag-atake

Sa pagpakita sa UC Browser makit-an nimo ang usa ka serbisyo nga adunay usa ka nagpatin-aw sa kaugalingon nga ngalan com.uc.deployment.UpgradeDeployService.

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

Sa diha nga kini nga serbisyo magsugod, ang browser naghimo sa usa ka POST hangyo sa puds.ucweb.com/upgrade/index.xhtml, nga makita sa trapiko pipila ka oras pagkahuman sa pagsugod. Agig tubag, mahimo siyang makadawat og usa ka sugo sa pag-download sa pipila ka update o bag-ong module. Atol sa pag-analisar, ang server wala maghatag sa ingon nga mga sugo, apan among namatikdan nga kung kami mosulay sa pag-abli sa usa ka PDF sa browser, kini naghimo sa ikaduha nga hangyo sa adres nga gipiho sa ibabaw, nga human niana kini nag-download sa lumad nga librarya. Aron mahimo ang pag-atake, nakahukom kami nga gamiton kini nga bahin sa UC Browser: ang abilidad sa pag-abli sa PDF gamit ang usa ka lumad nga librarya, nga wala sa APK ug nga kini nag-download gikan sa Internet kung gikinahanglan. Angay nga matikdan nga, sa teoretikal, ang UC Browser mahimong mapugos sa pag-download sa usa ka butang nga wala’y interaksyon sa gumagamit - kung naghatag ka usa ka maayong pagkaporma nga tubag sa usa ka hangyo nga gipatuman pagkahuman sa paglansad sa browser. Apan aron mahimo kini, kinahanglan namon nga tun-an ang protocol sa interaksyon sa server sa mas detalyado, mao nga nakahukom kami nga mas dali nga i-edit ang na-intercept nga tubag ug ilisan ang librarya alang sa pagtrabaho sa PDF.

Mao nga, kung gusto sa usa ka tiggamit nga magbukas sa usa ka PDF direkta sa browser, ang mga mosunud nga hangyo makita sa trapiko:

Pagpangita alang sa mga kahuyangan sa UC Browser

Una adunay usa ka POST nga hangyo sa puds.ucweb.com/upgrade/index.xhtml, unya
Usa ka archive nga adunay librarya alang sa pagtan-aw sa PDF ug mga format sa opisina gi-download. Makataronganon ang paghunahuna nga ang una nga hangyo nagpadala sa kasayuran bahin sa sistema (labing menos ang arkitektura aron mahatagan ang gikinahanglan nga librarya), ug agig tubag niini ang browser nakadawat pipila nga kasayuran bahin sa librarya nga kinahanglan i-download: ang adres ug, posible. , lain pa. Ang problema mao nga kini nga hangyo gi-encrypt.

Paghangyo nga tipik

Tubag nga tipik

Pagpangita alang sa mga kahuyangan sa UC Browser

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang librarya mismo giputos sa ZIP ug wala gi-encrypt.

Pagpangita alang sa mga kahuyangan sa UC Browser

Pangitaa ang traffic decryption code

Atong sulayan nga masabtan ang tubag sa server. Atong tan-awon ang code sa klase com.uc.deployment.UpgradeDeployService: gikan sa pamaagi onStartCommand adto sa com.uc.deployment.bx, ug gikan niini ngadto sa 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);
}

Nakita namon ang pagporma sa usa ka hangyo sa POST dinhi. Gihatagan namon ug pagtagad ang paghimo sa usa ka han-ay sa 16 bytes ug ang pagpuno niini: 0x5F, 0, 0x1F, -50 (=0xCE). Nahiuyon sa among nakita sa hangyo sa ibabaw.

Sa parehas nga klase makita nimo ang usa ka nested nga klase nga adunay lain nga makapaikag nga pamaagi:

        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");
}
}

Ang pamaagi nagkuha ug array sa byte isip input ug nagsusi nga ang zero byte kay 0x60 o ang ikatulo nga byte kay 0xD0, ug ang ikaduhang byte kay 1, 11 o 0x1F. Atong tan-awon ang tubag gikan sa server: ang zero byte mao ang 0x60, ang ikaduha mao ang 0x1F, ang ikatulo mao ang 0x60. Morag unsay atong gikinahanglan. Paghukom sa mga linya ("up_decrypt", pananglitan), usa ka pamaagi ang kinahanglan nga tawagan dinhi nga mag-decrypt sa tubag sa server.
Mopadayon kita sa pamaagi gj. Timan-i nga ang una nga argumento mao ang byte sa offset 2 (ie 0x1F sa among kaso), ug ang ikaduha mao ang tubag sa server nga wala
unang 16 byte.

     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;
}

Dayag, dinhi mipili kami og decryption algorithm, ug ang samang byte nga naa sa among
kaso nga katumbas sa 0x1F, nagpasabot sa usa sa tulo ka posibleng mga kapilian.

Nagpadayon kami sa pag-analisar sa code. Human sa usa ka magtiayon nga sa paglukso atong makita ang atong mga kaugalingon sa usa ka paagi uban sa usa ka-sa-kaugalingon pagpatin-aw nga ngalan decryptBytesByKey.

Dinhi duha pa ka byte ang gibulag gikan sa among tubag, ug usa ka string ang makuha gikan kanila. Klaro nga sa niini nga paagi ang yawe sa pag-decrypting sa mensahe gipili.

    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;
}

Sa pagtan-aw sa unahan, atong namatikdan nga sa niini nga yugto wala pa kita makakuha og usa ka yawe, apan ang "identifier" lamang niini. Ang pagkuha sa yawe mas komplikado.

Sa sunod nga pamaagi, duha pa ka mga parameter ang gidugang sa mga naa na, nga naghimo sa upat niini: ang magic nga numero 16, ang yawe nga identifier, ang naka-encrypt nga datos, ug usa ka dili masabtan nga pisi (sa among kaso, walay sulod).

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

Human sa usa ka serye sa mga transisyon moabut kami sa pamaagi staticBinarySafeDecryptNoB64 interface com.alibaba.wireless.security.open.staticdataencrypt.IStaticDataEncryptComponent. Walay mga klase sa main code sa aplikasyon nga nagpatuman niini nga interface. Adunay ingon nga klase sa file lib/armeabi-v7a/libsgmain.so, nga sa pagkatinuod dili usa ka .so, apan usa ka .jar. Ang pamaagi nga among interesado gipatuman sama sa mosunod:

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);
}
//...
}

Dinhi ang among lista sa mga parameter gidugangan sa duha pa ka integer: 2 ug 0. Paghukom pinaagi sa
tanan, 2 nagpasabot decryption, sama sa pamaagi doFinal sistema nga klase javax.crypto.Cipher. Ug kining tanan gibalhin sa usa ka piho nga Router nga adunay numero 10601 - dayag nga kini ang numero sa mando.

Human sa sunod nga kadena sa mga transisyon atong makita ang usa ka klase nga nagpatuman sa interface IRouterComponent ug pamaagi 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);
}
}

Ug klase usab JNICLlibrary, diin gideklarar ang lumad nga pamaagi doCommandNative:

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

Kini nagpasabut nga kinahanglan namon nga mangita usa ka pamaagi sa lumad nga code doCommandNative. Ug dinhi nagsugod ang kalingawan.

Paglibog sa code sa makina

Sa file libsgmain.so (nga sa tinuud usa ka .jar ug diin among nakit-an ang pagpatuman sa pipila nga mga interface nga may kalabotan sa pag-encrypt sa ibabaw) adunay usa ka lumad nga librarya: libsgmainso-6.4.36.so. Giablihan namo kini sa IDA ug nagkuha og usa ka hugpong sa mga dialog box nga adunay mga sayup. Ang problema kay ang section header table dili balido. Gihimo kini sa katuyoan aron makomplikado ang pagtuki.

Pagpangita alang sa mga kahuyangan sa UC Browser

Apan wala kini gikinahanglan: aron sa husto nga pag-load sa usa ka ELF file ug pag-analisar niini, igo na ang usa ka lamesa sa header sa programa. Busa, gitangtang lang namo ang lamesa sa seksyon, nga wala’y zero ang katugbang nga mga natad sa header.

Pagpangita alang sa mga kahuyangan sa UC Browser

Ablihi ang file sa IDA pag-usab.

Adunay duha ka mga paagi sa pagsulti sa Java virtual machine diin eksakto sa lumad nga librarya ang pagpatuman sa usa ka pamaagi nga gideklarar sa Java code isip lumad nahimutang. Ang una mao ang paghatag niini og ngalan sa espisye Java_package_name_ClassName_MethodName.

Ang ikaduha mao ang pagparehistro niini kung nagkarga sa librarya (sa function JNI_OnLoad)
gamit ang function call RegisterNatives.

Sa among kaso, kung gamiton namon ang una nga pamaagi, ang ngalan kinahanglan nga ingon niini: Java_com_taobao_wireless_security_adapter_JNICLlibrary_doCommandNative.

Wala’y ingon nga function taliwala sa mga gi-eksport nga mga gimbuhaton, nga nagpasabut nga kinahanglan nimo pangitaon ang usa ka tawag RegisterNatives.
Adto ta sa function JNI_OnLoad ug atong makita kini nga hulagway:

Pagpangita alang sa mga kahuyangan sa UC Browser

Unsa ang nahitabo dinhi? Sa una nga pagtan-aw, ang pagsugod ug katapusan sa function kasagaran alang sa arkitektura sa ARM. Ang una nga panudlo sa stack nagtipig sa mga sulud sa mga rehistro nga gamiton sa function sa operasyon niini (sa kini nga kaso, R0, R1 ug R2), ingon man ang mga sulud sa rehistro sa LR, nga adunay sulud nga adres sa pagbalik gikan sa function. . Ang katapusan nga panudlo nagpahiuli sa natipig nga mga rehistro, ug ang address sa pagbalik gibutang dayon sa rehistro sa PC - sa ingon mibalik gikan sa function. Apan kung imong tan-awon pag-ayo, imong mamatikdan nga ang penultimate nga panudlo nagbag-o sa pagbalik nga adres nga gitipigan sa stack. Atong kuwentahon kung unsa kini pagkahuman
pagpatuman sa code. Ang usa ka piho nga adres nga 1xB0 gikarga sa R130, ang 5 gikuha gikan niini, unya kini gibalhin sa R0 ug ang 0x10 gidugang niini. Kini nahimo nga 0xB13B. Sa ingon, ang IDA naghunahuna nga ang katapusan nga panudlo usa ka normal nga pagbalik sa function, apan sa tinuud kini moadto sa kalkulado nga adres 0xB13B.

Angayan nga hinumdoman dinhi nga ang mga processor sa ARM adunay duha ka mga mode ug duha ka set sa mga panudlo: ARM ug Thumb. Ang labing gamay nga hinungdanon nga bahin sa adres nagsulti sa processor kung unsang set sa panudlo ang gigamit. Sa ato pa, ang adres sa tinuud 0xB13A, ug ang usa sa labing gamay nga hinungdanon nga gamay nagpakita sa mode sa Thumb.

Ang susama nga "adapter" gidugang sa sinugdanan sa matag function niini nga librarya ug
kodigo sa basura. Dili na nato kini hisgotan sa detalye - hinumdoman lang nato
nga ang tinuod nga sinugdanan sa hapit tanan nga mga gimbuhaton medyo layo pa.

Tungod kay ang code dili klaro nga molukso sa 0xB13A, ang IDA mismo wala makaila nga ang code nahimutang sa kini nga lokasyon. Sa samang rason, wala kini makaila sa kadaghanan sa code sa library isip code, nga naghimo sa pagtuki nga medyo lisud. Gisultihan namon ang IDA nga kini ang code, ug kini ang mahitabo:

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang lamesa tin-aw nga nagsugod sa 0xB144. Unsay naa sa sub_494C?

Pagpangita alang sa mga kahuyangan sa UC Browser

Kung gitawag kini nga function sa rehistro sa LR, makuha namon ang adres sa nahisgutan na nga lamesa (0xB144). Sa R0 - index niini nga lamesa. Kana mao, ang bili gikuha gikan sa lamesa, gidugang sa LR ug ang resulta mao
ang adres nga adtoan. Atong sulayan ang pagkuwenta niini: 0xB144 + [0xB144 + 8* 4] = 0xB144 + 0x120 = 0xB264. Moadto kami sa nadawat nga adres ug tan-awa ang literal nga pipila ka mapuslanon nga mga panudlo ug moadto pag-usab sa 0xB140:

Pagpangita alang sa mga kahuyangan sa UC Browser

Karon adunay usa ka transisyon sa offset nga adunay index 0x20 gikan sa lamesa.

Sa paghukom sa gidak-on sa lamesa, adunay daghang mga transisyon sa code. Ang pangutana mitungha kung posible ba nga sa usa ka paagi atubangon kini nga mas awtomatiko, nga wala’y mano-mano nga pagkalkula sa mga adres. Ug ang mga script ug ang abilidad sa pag-patch sa code sa IDA makatabang kanamo:

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"

Ibutang ang cursor sa linya 0xB26A, padagana ang script ug tan-awa ang transisyon sa 0xB4B0:

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang IDA wala usab makaila niini nga lugar isip usa ka code. Gitabangan namo siya ug nakita ang laing disenyo didto:

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang mga instruksyon human sa BLX ingon og dili kaayo masabtan, kini sama sa usa ka matang sa pagbakwit. Atong tan-awon ang sub_4964:

Pagpangita alang sa mga kahuyangan sa UC Browser

Ug sa tinuud, dinhi gikuha ang usa ka dword sa adres nga nahimutang sa LR, gidugang sa kini nga adres, pagkahuman gikuha ang kantidad sa sangputanan nga adres ug gibutang sa stack. Usab, ang 4 gidugang sa LR aron nga pagkahuman sa pagbalik gikan sa function, kining parehas nga offset gilaktawan. Human niini ang POP {R1} nga sugo mokuha sa resulta nga bili gikan sa stack. Kung imong tan-awon kung unsa ang nahimutang sa address 0xB4BA + 0xEA = 0xB5A4, makakita ka usa ka butang nga susama sa usa ka lamesa sa address:

Pagpangita alang sa mga kahuyangan sa UC Browser

Aron ma-patch kini nga disenyo, kinahanglan nimo nga makakuha og duha ka mga parameter gikan sa code: ang offset ug ang numero sa rehistro diin gusto nimo ibutang ang resulta. Alang sa matag posible nga rehistro, kinahanglan nimo nga mag-andam daan usa ka piraso sa code.

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"

Atong ibutang ang cursor sa sinugdanan sa istruktura nga gusto namong ilisan - 0xB4B2 - ug ipadagan ang script:

Pagpangita alang sa mga kahuyangan sa UC Browser

Dugang pa sa nahisgotan na nga mga istruktura, ang code naglangkob usab sa mosunod:

Pagpangita alang sa mga kahuyangan sa UC Browser

Sama sa miaging kaso, pagkahuman sa panudlo sa BLX adunay usa ka offset:

Pagpangita alang sa mga kahuyangan sa UC Browser

Gikuha namon ang offset sa adres gikan sa LR, idugang kini sa LR ug adto didto. 0x72044 + 0xC = 0x72050. Ang script alang niini nga disenyo yano ra:

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"

Resulta sa pagpatuman sa script:

Pagpangita alang sa mga kahuyangan sa UC Browser

Sa higayon nga ang tanan ma-patched sa function, mahimo nimong itudlo ang IDA sa tinuod nga sinugdanan niini. Kini maghiusa sa tanan nga function code, ug kini mahimong ma-decompiled gamit ang HexRays.

Pag-decode sa mga string

Kami nakakat-on sa pag-atubang sa obfuscation sa machine code sa librarya libsgmainso-6.4.36.so gikan sa UC Browser ug nakadawat sa function code 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;
}

Atong tan-awon pag-ayo ang mosunod nga mga linya:

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

Sa function sub_73E24 ang ngalan sa klase klaro nga gi-decrypted. Ingon nga mga parameter niini nga function, usa ka pointer sa datos nga susama sa naka-encrypt nga datos, usa ka piho nga buffer ug usa ka numero ang gipasa. Dayag nga, pagkahuman sa pagtawag sa function, adunay usa ka decrypted nga linya sa buffer, tungod kay gipasa kini sa function. FindClass, nga nagkuha sa ngalan sa klase isip ikaduhang parameter. Busa, ang numero mao ang gidak-on sa buffer o ang gitas-on sa linya. Atong sulayan nga masabtan ang ngalan sa klase, kini kinahanglan nga magsulti kanato kung kita moadto sa husto nga direksyon. Atong tan-awon pag-ayo kon unsay mahitabo sa 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;
}

function sub_7AF78 nagmugna og usa ka pananglitan sa usa ka sudlanan alang sa byte arrays sa espesipikong gidak-on (dili kami maghisgot niini nga mga sudlanan sa detalye). Dinhi gihimo ang duha ka ingon nga mga sudlanan: ang usa adunay sulud nga linya "DcO/lcK+h?m3c*q@" (sayon ​​​​sa pagtag-an nga kini usa ka yawe), ang lain adunay sulud nga naka-encrypt nga datos. Sunod, ang duha nga mga butang gibutang sa usa ka piho nga istruktura, nga gipasa sa function sub_6115C. Atong markahan usab ang usa ka field nga adunay bili nga 3 niini nga istruktura. Atong tan-awon kung unsa ang sunod nga mahitabo niini nga istruktura.

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;
}

Ang switch parameter kay usa ka structure field nga kaniadto gi-assign sa value 3. Tan-awa ang case 3: sa function sub_6364C Ang mga parameter gipasa gikan sa istruktura nga gidugang didto sa miaging function, i.e. ang yawe ug naka-encrypt nga datos. Kung imong tan-awon pag-ayo sub_6364C, mahimo nimong mailhan ang RC4 algorithm niini.

Kami adunay usa ka algorithm ug usa ka yawe. Atong sulayan nga masabtan ang ngalan sa klase. Ania ang nahitabo: com/taobao/wireless/security/adapter/JNICLibrary. Nindot! Anaa kami sa husto nga dalan.

Command tree

Karon kinahanglan namong mangita og hagit RegisterNatives, nga magtudlo kanato sa function doCommandNative. Atong tan-awon ang mga gimbuhaton nga gitawag gikan sa JNI_OnLoad, ug atong makita kini sa 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;
}

Ug sa tinuud, usa ka lumad nga pamaagi nga adunay ngalan ang narehistro dinhi doCommandNative. Karon nahibal-an namon ang iyang adres. Tan-awon nato unsay iyang gibuhat.

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;
}

Pinaagi sa ngalan mahimo nimong matag-an nga ania ang entry point sa tanan nga mga gimbuhaton nga nakahukom sa mga developer nga ibalhin sa lumad nga librarya. Interesado kami sa function number 10601.

Makita nimo gikan sa code nga ang command number nagpatunghag tulo ka numero: sugo/10000, sugo % 10000 / 100 ΠΈ sugo% 10, i.e., sa among kaso, 1, 6 ug 1. Kining tulo ka numero, ingon man usa ka pointer sa Si JNIEnv ug ang mga argumento nga gipasa sa function gidugang sa usa ka istruktura ug gipasa. Gamit ang tulo ka mga numero nga nakuha (atong itudlo kanila ang N1, N2 ug N3), usa ka command tree ang gitukod.

Usa ka butang nga sama niini:

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang kahoy napuno sa dinamikong paagi JNI_OnLoad.
Tulo ka numero ang nag-encode sa agianan sa kahoy. Ang matag dahon sa kahoy naglangkob sa pocked address sa katugbang nga function. Ang yawe anaa sa parent node. Ang pagpangita sa lugar sa code diin ang function nga kinahanglan namon idugang sa kahoy dili lisud kung imong masabtan ang tanan nga mga istruktura nga gigamit (wala namon kini ihulagway aron dili mabuak ang usa ka dako na nga artikulo).

Dugang nga pagkalibog

Nadawat namo ang adres sa function nga kinahanglang mag-decrypt sa trapiko: 0x5F1AC. Apan sayo pa kaayo aron magmaya: ang mga nag-develop sa UC Browser nag-andam na usab nga sorpresa alang kanamo.

Human madawat ang mga parameter gikan sa laray nga naporma sa Java code, atong makuha
sa function sa address 0x4D070. Ug dinhi ang laing matang sa code obfuscation naghulat kanato.

Gibutang namon ang duha ka indeks sa R7 ug R4:

Pagpangita alang sa mga kahuyangan sa UC Browser

Gibalhin namon ang una nga indeks sa R11:

Pagpangita alang sa mga kahuyangan sa UC Browser

Aron makakuha usa ka adres gikan sa usa ka lamesa, gamita ang usa ka indeks:

Pagpangita alang sa mga kahuyangan sa UC Browser

Pagkahuman sa pag-adto sa una nga adres, gigamit ang ikaduha nga indeks, nga naa sa R4. Adunay 230 ka mga elemento sa lamesa.

Unsay buhaton niini? Mahimo nimong sultihan ang IDA nga kini usa ka switch: Edit -> Other -> Ipiho ang switch idiom.

Pagpangita alang sa mga kahuyangan sa UC Browser

Ang resulta nga code makalilisang. Apan, sa imong pag-agi sa lasang niini, imong mamatikdan ang usa ka tawag sa usa ka function nga pamilyar na kanamo sub_6115C:

Pagpangita alang sa mga kahuyangan sa UC Browser

Adunay usa ka switch diin sa kaso 3 adunay usa ka decryption gamit ang RC4 algorithm. Ug sa kini nga kaso, ang istruktura nga gipasa sa function napuno gikan sa mga parameter nga gipasa sa doCommandNative. Atong hinumduman kung unsa ang atong naa didto magicInt nga adunay kantidad nga 16. Gitan-aw namon ang katugbang nga kaso - ug pagkahuman sa daghang mga pagbag-o nakit-an namon ang code diin mailhan ang algorithm.

Pagpangita alang sa mga kahuyangan sa UC Browser

Kini ang AES!

Ang algorithm anaa, ang nahabilin mao ang pagkuha sa mga parameter niini: mode, yawe ug, posible, ang initialization vector (ang presensya niini nagdepende sa operating mode sa AES algorithm). Ang istruktura uban kanila kinahanglan nga maporma sa usa ka lugar sa wala pa ang tawag sa function sub_6115C, apan kini nga bahin sa code labi ka maayo nga na-obfuscated, mao nga ang ideya mitungha sa pag-patch sa code aron ang tanan nga mga parameter sa function sa decryption ihulog sa usa ka file.

Patch

Aron dili manu-mano ang pagsulat sa tanang patch code sa assembly language, mahimo nimong ilunsad ang Android Studio, pagsulat og function didto nga makadawat sa samang input parameters sama sa atong decryption function ug magsulat sa usa ka file, unya kopyaha-paste ang code nga himoon sa compiler. makamugna.

Ang among mga higala gikan sa UC Browser team nag-atiman usab sa kasayon ​​​​sa pagdugang sa code. Atong hinumduman nga sa sinugdanan sa matag function aduna kitay garbage code nga daling mapulihan sa uban. Kombenyente kaayo πŸ™‚ Bisan pa, sa sinugdanan sa target nga function wala’y igo nga wanang alang sa code nga nagtipig sa tanan nga mga parameter sa usa ka file. Kinahanglan nakong bahinon kini sa mga bahin ug gamiton ang mga bloke sa basura gikan sa silingang mga gimbuhaton. Adunay upat ka bahin sa kinatibuk-an.

Una nga bahin:

Pagpangita alang sa mga kahuyangan sa UC Browser

Sa arkitektura sa ARM, ang una nga upat nga mga parameter sa function gipasa sa mga rehistro nga R0-R3, ang nahabilin, kung adunay, gipasa sa stack. Ang LR register nagdala sa return address. Ang tanan niini kinahanglan nga maluwas aron ang function mahimo’g molihok pagkahuman sa paglabay sa mga parameter niini. Kinahanglan usab namo nga i-save ang tanan nga mga rehistro nga among gamiton sa proseso, mao nga among PUSH.W {R0-R10,LR}. Sa R7 atong makuha ang adres sa lista sa mga parameter nga gipasa sa function pinaagi sa stack.

Paggamit sa function fopen atong ablihan ang file /data/local/tmp/aes sa "ab" mode
i.e. alang sa pagdugang. Sa R0 gikarga namon ang adres sa ngalan sa file, sa R1 - ang adres sa linya nga nagpakita sa mode. Ug dinhi natapos ang code sa basura, mao nga nagpadayon kami sa sunod nga function. Aron kini magpadayon sa pagtrabaho, gibutang namon sa sinugdanan ang transisyon sa tinuud nga code sa function, pag-bypass sa basura, ug imbes sa basura gidugang namon ang pagpadayon sa patch.

Pagpangita alang sa mga kahuyangan sa UC Browser

Gitawag fopen.

Ang unang tulo ka mga parameter sa function AES naay type int. Tungod kay gitipigan namon ang mga rehistro sa stack sa sinugdanan, mahimo ra namon nga ipasa ang function f pagsulat ang ilang mga adres sa stack.

Pagpangita alang sa mga kahuyangan sa UC Browser

Sunod kami adunay tulo ka mga istruktura nga naglangkob sa gidak-on sa datos ug usa ka pointer sa datos alang sa yawe, inisyal nga vector ug naka-encrypt nga datos.

Pagpangita alang sa mga kahuyangan sa UC Browser

Sa katapusan, isira ang file, ibalik ang mga rehistro ug ibalhin ang kontrol sa tinuud nga function AES.

Among gikolekta ang usa ka APK nga adunay gi-patch nga librarya, gipirmahan kini, i-upload kini sa device/emulator, ug ilunsad kini. Nakita namon nga ang among dump gihimo, ug daghang datos ang gisulat didto. Ang browser naggamit sa encryption dili lamang alang sa trapiko, ug ang tanan nga encryption moagi sa function sa pangutana. Apan sa pipila ka rason ang gikinahanglan nga datos wala didto, ug ang gikinahanglan nga hangyo dili makita sa trapiko. Aron dili maghulat hangtud nga ang UC Browser deigns sa paghimo sa gikinahanglan nga hangyo, atong kuhaon ang encrypted nga tubag gikan sa server nga nadawat sa sayo pa ug patch sa aplikasyon pag-usab: idugang ang decryption sa onCreate sa nag-unang kalihokan.

    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

Nagtigum kami, nagpirma, nag-install, naglansad. Nakadawat kami og NullPointerException tungod kay ang pamaagi mibalik nga null.

Atol sa dugang nga pag-analisar sa code, usa ka function ang nadiskobrehan nga naghubad sa makapaikag nga mga linya: "META-INF/" ug ".RSA". Morag gi-verify sa aplikasyon ang sertipiko niini. O nagmugna pa gani og mga yawe gikan niini. Dili gyud ko gusto nga atubangon kung unsa ang nahitabo sa sertipiko, mao nga i-slip na lang naton kini sa husto nga sertipiko. Atong i-patch ang naka-encrypt nga linya aron imbes nga "META-INF/" makuha nato ang "BLABLINF/", paghimo og folder nga adunay kana nga ngalan sa APK ug idugang ang squirrel browser certificate didto.

Nagtipon kami, nagpirma, nag-install, naglansad. Bingo! Naa namo ang yawe!

MitM

Nakadawat kami usa ka yawe ug usa ka vector sa pagsugod nga parehas sa yawe. Atong sulayan nga i-decrypt ang tubag sa server sa CBC mode.

Pagpangita alang sa mga kahuyangan sa UC Browser

Nakita namon ang archive URL, usa ka butang nga susama sa MD5, "extract_unzipsize" ug usa ka numero. Among gisusi: ang MD5 sa archive parehas, ang gidak-on sa wala ma-pack nga librarya parehas. Kami naningkamot sa pag-patch niini nga librarya ug ihatag kini sa browser. Aron ipakita nga na-load ang among gi-patch nga librarya, maglunsad kami og Tuyo sa paghimo og SMS nga adunay teksto nga "PWNED!" Atong pulihan ang duha ka tubag gikan sa server: puds.ucweb.com/upgrade/index.xhtml ug sa pag-download sa archive. Sa una gipulihan namon ang MD5 (ang gidak-on dili mausab pagkahuman sa pag-unpack), sa ikaduha among gihatag ang archive nga adunay patched library.

Gisulayan sa browser nga i-download ang archive sa daghang beses, pagkahuman naghatag kini usa ka sayup. Dayag nga usa ka butang
dili siya ganahan. Ingon usa ka sangputanan sa pag-analisar niining murky nga format, nahimo nga ang server nagpadala usab sa gidak-on sa archive:

Pagpangita alang sa mga kahuyangan sa UC Browser

Gi-encode kini sa LEB128. Pagkahuman sa patch, ang gidak-on sa archive nga adunay librarya nausab gamay, mao nga giisip sa browser nga ang archive na-download nga hiwi, ug pagkahuman sa daghang mga pagsulay kini nagbutang usa ka sayup.

Gi-adjust namo ang gidak-on sa archive... Ug – kadaugan! πŸ™‚ Ang resulta naa sa video.

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

Mga sangputanan ug reaksyon sa developer

Sa samang paagi, ang mga hacker mahimong mogamit sa dili kasegurohan nga bahin sa UC Browser sa pag-apod-apod ug pagpadagan sa mga malisyoso nga librarya. Kini nga mga librarya molihok sa konteksto sa browser, aron madawat nila ang tanan nga pagtugot sa sistema niini. Ingon usa ka sangputanan, ang abilidad sa pagpakita sa mga bintana sa phishing, ingon man ang pag-access sa mga nagtrabaho nga file sa orange nga Chinese squirrel, lakip ang mga login, password ug cookies nga gitipigan sa database.

Gikontak namon ang mga nag-develop sa UC Browser ug gipahibalo sila bahin sa problema nga among nakit-an, gisulayan nga ipunting ang pagkahuyang ug ang peligro niini, apan wala sila maghisgot bisan unsa kanamo. Sa kasamtangan, ang browser nagpadayon sa pagpakita sa makuyaw nga bahin niini sa yano nga pagtan-aw. Apan sa dihang gipadayag na namo ang mga detalye sa kahuyang, dili na mahimo nga ibaliwala kini sama kaniadto. Marso 27 diay
usa ka bag-ong bersyon sa UC Browser 12.10.9.1193 ang gipagawas, nga naka-access sa server pinaagi sa HTTPS: puds.ucweb.com/upgrade/index.xhtml.

Dugang pa, pagkahuman sa "pag-ayo" ug hangtod sa panahon sa pagsulat niini nga artikulo, ang pagsulay sa pag-abli sa usa ka PDF sa usa ka browser miresulta sa usa ka mensahe sa sayup nga adunay teksto nga "Oops, adunay sayup!" Ang usa ka hangyo sa server wala gihimo sa dihang misulay sa pag-abli sa usa ka PDF, apan ang usa ka hangyo gihimo sa diha nga ang browser gilusad, nga nagpakita sa padayon nga abilidad sa pag-download sa executable code sa paglapas sa mga lagda sa Google Play.

Source: www.habr.com

Idugang sa usa ka comment