Ag lorg leochaileachtaí i mBrabhsálaí UC

Ag lorg leochaileachtaí i mBrabhsálaí UC

Réamhrá

Ag deireadh mhí an Mhárta táimid tuairiscithe, gur aimsigh siad cumas folaithe chun cód neamhfhíoraithe a luchtú agus a rith i mBrabhsálaí UC. Sa lá atá inniu déanfaimid breathnú go mion ar conas a tharlaíonn an íoslódáil seo agus conas is féidir le hackers é a úsáid chun a gcríoch féin.

Tamall ó shin, fógraíodh agus dáileadh Brabhsálaí UC go han-ionsaitheach: suiteáladh é ar ghléasanna úsáideoirí ag baint úsáide as malware, a dháileadh ó shuímh éagsúla faoi chruth comhaid físe (i.e., shíl úsáideoirí go raibh siad ag íoslódáil, mar shampla, físeán porn, ach ina ionad sin fuair APK leis an mbrabhsálaí seo), úsáid meirgí scanrúla le teachtaireachtaí go raibh an brabhsálaí as dáta, leochaileach, agus rudaí mar sin. Sa ghrúpa oifigiúil Brabhsálaí UC ar VK tá téama, inar féidir le húsáideoirí gearán a dhéanamh faoi fhógraíocht éagórach, tá go leor samplaí ann. I 2016 bhí fiú fógraíocht físeáin i Rúisis (tá, fógraíocht do bhrabhsálaí ad-blocála).

Agus é seo á scríobh, tá breis agus 500 suiteálacha ag Brabhsálaí UC ar Google Play. Tá sé seo go hiontach - níl níos mó ag Google Chrome ach amháin. I measc na n-athbhreithnithe is féidir leat go leor gearán a fheiceáil faoi fhógraíocht agus atreoruithe chuig roinnt feidhmchlár ar Google Play. Ba é seo an chúis lenár dtaighde: shocraigh muid féachaint an raibh Brabhsálaí UC ag déanamh rud éigin dona. Agus d'éirigh sé amach go ndéanann sé!

Sa chód iarratais, thángthas ar an gcumas cód inrite a íoslódáil agus a rith, atá contrártha leis na rialacha maidir le hiarratais a fhoilsiú ar Google Play. Chomh maith le cód inrite a íoslódáil, déanann Brabhsálaí UC amhlaidh ar bhealach neamhchinnte, ar féidir é a úsáid chun ionsaí MitM a sheoladh. Féachaimis an féidir linn ionsaí den sórt sin a dhéanamh.

Tá gach rud atá scríofa thíos ábhartha don leagan de Brabhsálaí UC a bhí ar fáil ar Google Play ag am an staidéir:

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

Veicteoir ionsaí

Sa léiriúchán Brabhsálaí UC is féidir leat seirbhís a aimsiú a bhfuil ainm féinmhínithe air com.uc.deployment.UpgradeDeployService.

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

Nuair a thosaíonn an tseirbhís seo, déanann an brabhsálaí iarratas POST chun puds.ucweb.com/upgrade/index.xhtml, atá le feiceáil sa trácht tamall tar éis an tosaithe. Mar fhreagra air sin, féadfaidh sé ordú a fháil chun nuashonrú nó modúl nua éigin a íoslódáil. Le linn na hanailíse, níor thug an freastalaí orduithe den sórt sin, ach thugamar faoi deara nuair a dhéanaimid iarracht PDF a oscailt sa bhrabhsálaí, go ndéanann sé an dara hiarratas chuig an seoladh a shonraítear thuas, agus ina dhiaidh sin íoslódálann sé an leabharlann dúchais. Chun an t-ionsaí a dhéanamh, shocraigh muid an ghné seo de Brabhsálaí UC a úsáid: an cumas PDF a oscailt ag baint úsáide as leabharlann dúchais, nach bhfuil san APK agus a íoslódálann sé ón Idirlíon más gá. Is fiú a thabhairt faoi deara, go teoiriciúil, gur féidir iallach a chur ar Brabhsálaí UC rud éigin a íoslódáil gan idirghníomhaíocht úsáideora - má sholáthraíonn tú freagra dea-chruthaithe ar iarratas a fhorghníomhaítear tar éis an brabhsálaí a sheoladh. Ach chun é seo a dhéanamh, ní mór dúinn staidéar níos mine a dhéanamh ar an bprótacal idirghníomhaíochta leis an bhfreastalaí, agus mar sin shocraigh muid go mbeadh sé níos éasca an freagra idircheapadh a chur in eagar agus an leabharlann a athsholáthar chun oibriú le PDF.

Mar sin, nuair is mian le húsáideoir PDF a oscailt go díreach sa bhrabhsálaí, is féidir na hiarratais seo a leanas a fheiceáil sa trácht:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ar dtús tá iarratas POST chun puds.ucweb.com/upgrade/index.xhtml, ansin
Íoslódáltar cartlann le leabharlann chun PDF agus formáidí oifige a fheiceáil. Tá sé loighciúil glacadh leis go dtarchuireann an chéad iarratas faisnéis faoin gcóras (ar a laghad an ailtireacht chun an leabharlann riachtanach a sholáthar), agus mar fhreagra air faigheann an brabhsálaí roinnt faisnéise faoin leabharlann is gá a íoslódáil: an seoladh agus, b'fhéidir , rud éigin eile. Is í an fhadhb atá ann go bhfuil an t-iarratas criptithe.

Blúire iarratais

Freagra blúire

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tá an leabharlann féin pacáistithe i ZIP agus níl sí criptithe.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Cuardaigh cód díchriptithe tráchta

Déanaimis iarracht freagra an fhreastalaí a aimsiú. Breathnaímid ar chód an ranga com.uc.deployment.UpgradeDeployService: ó mhodh onStartCommand Téigh com.uc.imscaradh.bx, agus uaidh go 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);
}

Feicimid foirm iarratais POST anseo. Tugaimid aird ar chruthú sraith de 16 bytes agus a líonadh: 0x5F, 0, 0x1F, -50 (= 0xCE). Comhthráthach leis an méid a chonaic muid san iarratas thuas.

Sa rang céanna is féidir leat rang neadaithe a fheiceáil a bhfuil modh suimiúil eile aige:

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

Glacann an modh sraith beart mar ionchur agus seiceálann sé gurb é 0x60 an beart náid nó gurb é 0xD0 an tríú beart, agus gurb é 1, 11 nó 0x1F an dara beart. Breathnaímid ar an bhfreagra ón bhfreastalaí: is é 0x60 an beart nialasach, is é 0x1F an dara ceann, is é 0x60 an tríú. Fuaimeanna cosúil le cad is gá dúinn. Ag breithiúnas de réir na línte (“up_decrypt”, mar shampla), ba cheart modh a ghlaoch anseo a dhíchripfidh freagra an fhreastalaí.
A ligean ar bogadh ar aghaidh go dtí an modh gj. Tabhair faoi deara gurb é an chéad argóint an beart ag fritháireamh 2 (i.e. 0x1F inár gcás), agus is é an dara ceann freagra an fhreastalaí gan
an chéad 16 beart.

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

Ar ndóigh, roghnaímid anseo algartam díchriptithe, agus an beart céanna atá inár gcuid
cás comhionann le 0x1F, seasann ceann amháin de thrí rogha féideartha.

Leanaimid ag déanamh anailíse ar an gcód. Tar éis cúpla léim aimsímid sinn féin i modh le hainm féinmhínitheach díchriptighBytesByKey.

Anseo tá dhá bheart eile scartha ónár bhfreagra, agus faightear sreang uathu. Is léir gur ar an mbealach seo a roghnaítear an eochair chun an teachtaireacht a dhíchriptiú.

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

Ag féachaint romhainn, tugaimid faoi deara nach bhfuil eochair faighte againn go fóill ag an gcéim seo, ach a “aitheantas” amháin. Tá sé beagán níos casta an eochair a fháil.

Sa chéad mhodh eile, cuirtear dhá pharaiméadar níos mó leis na cinn atá ann cheana féin, rud a fhágann go bhfuil ceithre cinn acu: an uimhir draíochta 16, an t-aitheantóir eochair, na sonraí criptithe, agus teaghrán dothuigthe (inár gcás, folamh).

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

Tar éis sraith aistrithe sroicheann muid an modh staticBinarySafeDecryptNoB64 comhéadan com.alibaba.wireless.slándáil.oscailte.staticdataencrypt.IStaticDataEncryptComponent. Níl aon ranganna sa phríomhchód feidhmchláir a chuireann an comhéadan seo i bhfeidhm. Tá a leithéid de rang sa chomhad lib/armeabi-v7a/libsgmain.so, nach bhfuil i ndáiríre a .so, ach .jar. Cuirtear an modh a bhfuil suim againn ann i bhfeidhm mar seo a leanas:

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

Seo ár liosta paraiméadair a fhorlíonadh le dhá slánuimhir eile: 2 agus 0. Ag breith ar
gach rud, ciallaíonn 2 díchriptiú, mar atá sa mhodh doCríoch rang córais javax.crypto.Cipher. Agus aistrítear seo go léir chuig Ródaire áirithe leis an uimhir 10601 - is cosúil gurb é seo an uimhir ordaithe.

Tar éis an chéad slabhra aistrithe eile aimsímid rang a chuireann an comhéadan i bhfeidhm Comhpháirt IRouter agus modh 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);
}
}

Agus freisin rang JNICLlibrary, ina ndearbhaítear an modh dúchais doCommandNative:

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

Ciallaíonn sé seo go gcaithfimid modh a aimsiú sa chód dúchais doCommandNative. Agus seo nuair a thosaíonn an spraoi.

Cearrbhachas cód meaisín

I gcomhad libsgmain.so (arb é .jar é i ndáiríre agus ina bhfuaireamar feidhmiú roinnt comhéadain a bhaineann le criptiú díreach thuas) tá leabharlann dhúchais amháin: libsgmainso-6.4.36.so. Osclaímid é san IDA agus faighimid a lán boscaí dialóige le hearráidí. Is í an fhadhb atá ann go bhfuil an tábla ceanntásc alt neamhbhailí. Déantar é seo d'aon ghnó chun an anailís a dhéanamh níos casta.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ach níl sé ag teastáil: chun comhad ELF a luchtú i gceart agus anailís a dhéanamh air, is leor tábla ceanntásca cláir. Mar sin, ní dhéanaimid ach an tábla alt a scriosadh, ag nialasú na réimsí comhfhreagracha sa cheanntásc.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Oscail an comhad in IDA arís.

Tá dhá bhealach ann a insint don mheaisín fíorúil Java cá háit go díreach sa leabharlann dhúchais a bhfuil cur i bhfeidhm modh a dhearbhaítear i gcód Java mar dhúchas suite. Is é an chéad cheann ná ainm speiceas a thabhairt dó Java_package_name_ClassName_MethodName.

Is é an dara ceann é a chlárú agus an leabharlann á luchtú (san fheidhm JNI_Ar Luchtaigh)
ag baint úsáide as glao feidhme ClárNatives.

Inár gcás, má úsáidimid an chéad mhodh, ba chóir go mbeadh an t-ainm mar seo: Java_com_taobao_wireless_security_adapter_JNICLibrary_doCommandNative.

Níl aon fheidhm den sórt sin i measc na bhfeidhmeanna a onnmhairítear, rud a chiallaíonn go gcaithfidh tú glao a lorg ClárNatives.
A ligean ar dul go dtí an fheidhm JNI_Ar Luchtaigh agus feicimid an pictiúr seo:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Cad atá ar siúl anseo? Ar an gcéad amharc, tá tús agus deireadh na feidhme tipiciúil le haghaidh ailtireacht ARM. Stórálann an chéad treoir ar an gcruach ábhar na gclár a úsáidfidh an fheidhm ina hoibriú (sa chás seo, R0, R1 agus R2), chomh maith le hábhar an chláir LR, ina bhfuil an seoladh fillte ón bhfeidhm . Déanann an treoir dheireanach na cláir shábháilte a athbhunú, agus cuirtear an seoladh fillte láithreach sa chlár PC - agus mar sin ag filleadh ón bhfeidhm. Ach má fhéachann tú go géar, tabharfaidh tú faoi deara go n-athraíonn an treoir leathdhéanach an seoladh fillte atá stóráilte ar an stack. Déanaimis ríomh conas a bheidh sé ina dhiaidh sin
cód a fhorghníomhú. Tá seoladh áirithe 1xB0 luchtaithe isteach i R130, déantar 5 a dhealú uaidh, ansin aistrítear é go R0 agus cuirtear 0x10 leis. Casadh sé amach 0xB13B. Mar sin, is dóigh leis an IDA gur tuairisceán gnáthfheidhme an treoir dheireanach, ach i ndáiríre tá sé ag dul chuig an seoladh ríofa 0xB13B.

Is fiú a mheabhrú anseo go bhfuil dhá mhodh agus dhá shraith treoracha ag próiseálaithe ARM: ARM agus Thumb. Insíonn an píosa is lú suntas den seoladh don phróiseálaí cén tacar treoracha atá in úsáid. Is é sin, is é 0xB13A an seoladh i ndáiríre, agus léiríonn ceann amháin sa ghiotán is lú an modh Ordóg.

Tá “oiriúnaitheoir” cosúil leis curtha le tús gach feidhme sa leabharlann seo agus
cód truflais. Ní mhairfimid go mion orthu níos mó - ní cuimhin linn ach
go bhfuil fíor-thús beagnach gach feidhm beagán níos faide ar shiúl.

Ós rud é nach léimeann an cód go sainráite go 0xB13A, níor aithin an IDA féin go raibh an cód suite ag an suíomh seo. Ar an gcúis chéanna, ní aithníonn sé an chuid is mó den chód sa leabharlann mar chód, rud a fhágann go bhfuil anailís beagán deacair. Deirimid leis an IDA gurb é seo an cód, agus seo mar a tharlaíonn:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tosaíonn an tábla go soiléir ag 0xB144. Cad atá i bhfo_494C?

Ag lorg leochaileachtaí i mBrabhsálaí UC

Nuair a ghlaoimid an fheidhm seo sa chlár LR, faighimid seoladh an tábla a luadh cheana (0xB144). I R0 - innéacs sa tábla seo. Is é sin, tógtar an luach ón tábla, cuirtear le LR agus is é an toradh
an seoladh chun dul go dtí. Déanaimis iarracht é a ríomh: 0xB144 + [0xB144 + 8* 4] = 0xB144 + 0x120 = 0xB264. Téann muid chuig an seoladh faighte agus feicimid go litriúil cúpla treoracha úsáideacha agus arís téigh go dtí 0xB140:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Anois beidh trasdul ar fhritháireamh le hinnéacs 0x20 ón tábla.

Ag breithiúnas de réir mhéid an tábla, beidh go leor aistrithe den sórt sin sa chód. Éiríonn an cheist an féidir déileáil leis seo ar bhealach níos huathoibríoch, gan seoltaí a ríomh de láimh. Agus tagann scripteanna agus an cumas cód a phaisteáil san IDA chun ár gcabhair:

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"

Cuir an cúrsóir ar líne 0xB26A, rith an script agus féach ar an aistriú go 0xB4B0:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Arís níor aithin IDA an réimse seo mar chód. Cabhraímid léi agus feicimid dearadh eile ansin:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Is cosúil nach bhfuil mórán ciall leis na treoracha tar éis BLX, tá sé níos cosúla le díláithriú de chineál éigin. Breathnaímid ar sub_4964:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Agus go deimhin, anseo tógtar dword ag an seoladh atá suite i LR, curtha leis an seoladh seo, ina dhiaidh sin tógtar an luach ag an seoladh mar thoradh air agus é a chur ar an gcruach. Chomh maith leis sin, cuirtear 4 le LR ionas gur féidir an fritháireamh céanna a dhéanamh tar éis filleadh ón bhfeidhm. Ina dhiaidh sin glacann an t-ordú POP {R1} an luach mar thoradh air ón gcruach. Má fhéachann tú ar a bhfuil suite ag seoladh 0xB4BA + 0xEA = 0xB5A4, feicfidh tú rud éigin cosúil le tábla seoltaí:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Chun an dearadh seo a phaisteáil, beidh ort dhá pharaiméadar a fháil ón gcód: an fritháireamh agus an cláruimhir inar mian leat an toradh a chur. I gcás gach clár féideartha, beidh ort píosa cód a ullmhú roimh ré.

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"

Cuirimid an cúrsóir ag tús an struchtúir a theastaíonn uainn a athsholáthar - 0xB4B2 - agus ritheann muid an script:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Chomh maith leis na struchtúir atá luaite cheana féin, tá an méid seo a leanas sa chód freisin:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Mar a tharla sa chás roimhe seo, tar éis an teagaisc BLX tá fritháireamh ann:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tógaimid an fhritháireamh chuig an seoladh ó LR, cuirimid chuig LR é agus téigh ann. 0x72044 + 0xC = 0x72050. Tá an script don dearadh seo simplí go leor:

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"

Toradh rith na scripte:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Nuair a bheidh gach rud patráilte san fheidhm, is féidir leat an IDA a dhíriú ar a thús fíor. Déanfaidh sé an cód feidhme go léir a phíosa le chéile, agus is féidir é a dhí-dhlúthú le HexRays.

Teaghráin díchódaithe

Táimid tar éis a fhoghlaim conas déileáil le obfuscation an chóid meaisín sa leabharlann libsgmainso-6.4.36.so ó Brabhsálaí UC agus fuair sé an cód feidhme JNI_Ar Luchtaigh.

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

Breathnaímis níos géire ar na línte seo a leanas:

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

I bhfeidhm fo_73E24 is léir go bhfuil ainm an ranga á dhíchriptiú. Mar pharaiméadair don fheidhm seo, cuirtear pointeoir ar shonraí cosúil le sonraí criptithe, maolán áirithe agus uimhir ar aghaidh. Ar ndóigh, tar éis an fheidhm a ghlaoch, beidh líne dhíchriptithe sa mhaolán, ós rud é go gcuirtear ar aghaidh chuig an bhfeidhm é AimsighRang, a ghlacann ainm an ranga mar an dara paraiméadar. Dá bhrí sin, is é an uimhir méid an mhaoláin nó fad na líne. Déanaimis iarracht ainm an ranga a dhéanamh amach, ba chóir go n-inseodh sé dúinn an bhfuil muid ag dul sa treo ceart. Breathnaímis ar cad a tharlaíonn i fo_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;
}

Feidhm fo_7AF78 cruthaíonn sé sampla de choimeádán le haghaidh eagair beart den mhéid sonraithe (ní fhanfaimid go mion ar na coimeádáin seo). Anseo cruthaítear dhá choimeádán den sórt sin: tá an líne i gceann amháin "DcO/lcK+h?m3c*q@" (is furasta buille faoi thuairim gur eochair é seo), tá sonraí criptithe sa cheann eile. Ansin, cuirtear an dá réad i struchtúr áirithe, a chuirtear ar aghaidh chuig an bhfeidhm fo_6115C. Déanaimis réimse a mharcáil freisin le luach 3 sa struchtúr seo. Féachaimis cad a tharlóidh don struchtúr seo ina dhiaidh sin.

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

Is réimse struchtúir é an paraiméadar lasc a sannadh an luach roimhe seo 3. Féach ar chás 3: leis an bhfeidhm fo_6364C cuirtear paraiméadair ar aghaidh ón struchtúr a cuireadh leis san fheidhm roimhe sin, i.e. an eochair agus na sonraí criptithe. Má fhéachann tú go géar ar fo_6364C, is féidir leat an algartam RC4 a aithint ann.

Tá algartam agus eochair againn. Déanaimis iarracht ainm an ranga a dhéanamh amach. Seo an méid a tharla: com/taobao/gan sreang/security/adapter/JNICLibrary. Go hiontach! Táimid ar an mbóthar ceart.

Crann ordú

Anois caithfimid dúshlán a aimsiú ClárNatives, a chuirfidh an fheidhm in iúl dúinn doCommandNative. A ligean ar breathnú ar na feidhmeanna a dtugtar ó JNI_OnLod, agus faighimid i fo_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;
}

Agus go deimhin, tá modh dúchais leis an ainm cláraithe anseo doCommandNative. Anois tá a sheoladh ar eolas againn. A ligean ar a fheiceáil cad a dhéanann sé.

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

Faoin ainm is féidir leat buille faoi thuairim gurb é anseo pointe iontrála na bhfeidhmeanna go léir a chinn na forbróirí a aistriú chuig an leabharlann dúchais. Tá suim againn i bhfeidhm uimhir 10601.

Is féidir leat a fheiceáil ón gcód go dtáirgeann an uimhir ordaithe trí uimhir: ordú/10000, ordú % 10000/100 и ordú % 10, i.e., inár gcás, 1, 6 agus 1. Tá na trí uimhir seo, chomh maith le pointeoir chuig JNIENv agus cuirtear struchtúr leis na hargóintí a chuirtear ar aghaidh chuig an bhfeidhm agus cuirtear ar aghaidh iad. Ag baint úsáide as na trí uimhir a fuarthas (cuirimis in iúl iad N1, N2 agus N3), tógtar crann ordaithe.

Rud éigin mar seo:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Líontar an crann isteach go dinimiciúil JNI_Ar Luchtaigh.
Ionchódaíonn trí uimhir an cosán sa chrann. Tá seoladh póca na feidhme comhfhreagrach i ngach duilleog den chrann. Tá an eochair sa nód tuismitheora. Níl sé deacair an áit sa chód a bhfuil an fheidhm atá ag teastáil uainn a chur leis an gcrann má thuigeann tú na struchtúir go léir a úsáidtear (ní dhéanaimid cur síos orthu ionas nach gcuirfí bloat ar alt sách mór).

Níos mó obfuscation

Fuaireamar seoladh na feidhme ar cheart trácht a dhíchriptiú: 0x5F1AC. Ach tá sé ró-luath le lúcháir a dhéanamh: d’ullmhaigh forbróirí Brabhsálaí UC iontas eile dúinn.

Tar éis na paraiméadair a fháil ón eagar a bunaíodh sa chód Java, faigheann muid
chuig an bhfeidhm ag seoladh 0x4D070. Agus anseo tá cineál eile de obfuscation cód ag fanacht linn.

Chuireamar dhá innéacs i R7 agus R4:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Aistrímid an chéad innéacs go R11:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Chun seoladh a fháil ó thábla, úsáid innéacs:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tar éis dul go dtí an chéad seoladh, úsáidtear an dara innéacs, atá i R4. Tá 230 eilimint sa tábla.

Cad atá le déanamh faoi? Is féidir leat a rá le IDA gur lasc é seo: Edit -> Eile -> Sonraigh lasc idiom.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tá an cód mar thoradh air scanrúil. Ach, ag déanamh do bhealach tríd an dufair, is féidir leat fógra a thabhairt do ghlaoch chuig feidhm atá ar eolas againn cheana féin fo_6115C:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Bhí lasc ann agus i gcás 3 bhí díchriptiú ag baint úsáide as an algartam RC4. Agus sa chás seo, líontar an struchtúr a chuirtear ar aghaidh chuig an bhfeidhm ó na paraiméadair a cuireadh ar aghaidh chuig doCommandNative. Cuimhnímis ar a raibh againn ansin draíocht Int leis an luach 16. Breathnaímid ar an gcás comhfhreagrach - agus tar éis roinnt aistrithe faighimid an cód trína bhféadfar an algartam a aithint.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Seo é AES!

Tá an algartam ann, níl fágtha ach a pharaiméadair a fháil: modh, eochair agus, b'fhéidir, an veicteoir tosaigh (braitheann a láithreacht ar mhodh oibriúcháin an algartam AES). Ní mór an struchtúr leo a bheith déanta áit éigin roimh an nglao feidhme fo_6115C, ach tá an chuid seo den chód obfuscated go háirithe go maith, mar sin éiríonn an smaoineamh a paiste an cód ionas go bhfuil gach paraiméadair na feidhme díchriptithe a dhumpáil isteach i gcomhad.

Paiste

Chun gan an cód paiste go léir a scríobh de láimh i dteanga tionóil, is féidir leat Android Studio a sheoladh, feidhm a scríobh ann a fhaigheann na paraiméadair ionchuir chéanna lenár bhfeidhm díchriptithe agus a scríobhann chuig comhad, ansin cóip-greamaigh an cód a dhéanfaidh an tiomsaitheoir. giniúint.

Thug ár gcairde ó fhoireann Brabhsálaí UC aire freisin don áisiúlacht a bhaineann le cód a chur leis. Lig dúinn cuimhneamh go bhfuil ag tús gach feidhm againn cód truflais is féidir a chur in ionad go héasca le haon cheann eile. An-áisiúil 🙂 Mar sin féin, ag tús na feidhme sprice níl go leor spáis ann don chód a shábhálann na paraiméadair go léir i gcomhad. Bhí orm é a roinnt ina chodanna agus úsáid a bhaint as bloic truflais ó fheidhmeanna comharsanacha. Bhí ceithre chuid san iomlán.

An chéad chuid:

Ag lorg leochaileachtaí i mBrabhsálaí UC

San ailtireacht ARM, cuirtear na chéad cheithre pharaiméadar feidhme trí chláir R0-R3, cuirtear an chuid eile, más ann dóibh, tríd an gcruach. Tá an seoladh fillte ar an gclár ó chlé. Ní mór é seo go léir a shábháil ionas gur féidir leis an bhfeidhm oibriú tar éis dúinn a paraiméadair a dhumpáil. Ní mór dúinn freisin na cláir go léir a úsáidfimid sa phróiseas a shábháil, mar sin déanaimid PUSH.W {R0-R10,LR}. In R7 faighimid seoladh liosta na bparaiméadar a chuirtear ar aghaidh chuig an bhfeidhm tríd an gcruach.

Ag baint úsáide as an bhfeidhm fopen a ligean ar oscailt an comhad /sonraí/áitiúil/tmp/aes i mód "ab".
i.e. le haghaidh breisithe. I R0 luchtú againn an seoladh an t-ainm comhaid, i R1 - an seoladh na líne a léiríonn an modh. Agus anseo críochnaíonn an cód truflais, mar sin bogaimid ar aghaidh go dtí an chéad fheidhm eile. D'fhonn é a leanúint ar aghaidh ag obair, chuir muid ag an tús an t-aistriú go dtí an cód fíor na feidhme, ag seachaint an truflais, agus in ionad an truflais cuirimid leanúint ar aghaidh leis an paiste.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ag glaoch fopen.

Na chéad trí pharaiméadair na feidhme aes bhfuil cineál int. Ós rud é gur shábháil muid na cláir go dtí an stack ag an tús, is féidir linn an fheidhm a chur ar aghaidh go simplí scríobh a gcuid seoltaí ar an gcruach.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ansin tá trí struchtúr againn ina bhfuil méid na sonraí agus pointeoir chuig na sonraí don eochair, veicteoir tosaigh agus sonraí criptithe.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Ag an deireadh, dún an comhad, cuir na cláir ar ais agus aistrigh an rialú chuig an bhfíorfheidhm aes.

Bailímid APK le leabharlann paistí, sínímid é, uaslódálann muid é chuig an ngléas/aithriseoir, agus seolann muid é. Feicimid go bhfuil ár dumpáil á chruthú, agus go leor sonraí á scríobh ann. Úsáideann an brabhsálaí criptiú ní hamháin le haghaidh tráchta, agus téann gach criptiú tríd an bhfeidhm atá i gceist. Ach ar chúis éigin níl na sonraí riachtanacha ann, agus níl an t-iarratas riachtanach le feiceáil sa trácht. Chun gan fanacht go dtí go ndaonnóidh Brabhsálaí UC an t-iarratas riachtanach a dhéanamh, tógfaimid an freagra criptithe ón bhfreastalaí a fuarthas níos luaithe agus paiste a chur leis an bhfeidhmchlár arís: cuir an díchriptiú le onCreate of the main activity.

    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

Bailímid, sínímid, suiteáil, seoladh. Faighimid NullPointerException toisc gur cuireadh an modh ar ais ar neamhní.

Le linn tuilleadh anailíse a dhéanamh ar an gcód, thángthas ar fheidhm a shainíonn línte suimiúla: “META-INF/” agus “.RSA”. Tá an chuma ar an scéal go bhfuil a theastas á fhíorú ag an bhfeidhmchlár. Nó gineann fiú eochracha uaidh. Níl mé ag iarraidh déileáil leis an méid atá ag tarlú leis an deimhniú, mar sin ní dhéanfaimid ach an deimhniú ceart a shleamhnú dó. Déanaimis an líne criptithe a phaisteáil ionas go bhfaighimid “BLABLINF/” in ionad “META-INF/”, cruthaímid fillteán leis an ainm sin san APK agus cuirfimid an teastas brabhsálaí iora ann.

Bailímid, sínímid, suiteáil, seoladh. Biongó! Tá an eochair againn!

MitM

Fuaireamar eochair agus veicteoir túsaithe cothrom leis an eochair. Déanaimis iarracht freagra an fhreastalaí a dhíchriptiú i mód CBC.

Ag lorg leochaileachtaí i mBrabhsálaí UC

Feicimid URL na cartlainne, rud éigin cosúil le MD5, “extract_unzipsize” agus uimhir. Déanaimid seiceáil: tá MD5 na cartlainne mar an gcéanna, tá méid na leabharlainne neamhphacáilte mar an gcéanna. Táimid ag iarraidh an leabharlann seo a phaisteáil agus a thabhairt don bhrabhsálaí. Chun a thaispeáint go bhfuil ár leabharlann paiste lódáilte, seolfaimid Intinn chun SMS a chruthú leis an téacs “PWNED!” Déanfaimid dhá fhreagra ón bhfreastalaí a athsholáthar: puds.ucweb.com/upgrade/index.xhtml agus an chartlann a íoslódáil. Ar an gcéad cuirimid MD5 in ionad (ní athraíonn an méid tar éis díphacáil), sa dara ceann tugann muid an chartlann leis an leabharlann paiste.

Déanann an brabhsálaí iarracht an chartlann a íoslódáil arís agus arís eile, agus ina dhiaidh sin tugann sé earráid. Cosúil rud éigin
ní maith leis. Mar thoradh ar anailís a dhéanamh ar an bhformáid dhubh seo, tharla go dtarchuireann an freastalaí méid na cartlainne freisin:

Ag lorg leochaileachtaí i mBrabhsálaí UC

Tá sé ionchódaithe i LEB128. Tar éis an paiste, d'athraigh méid na cartlainne leis an leabharlann beagán, agus mar sin mheas an brabhsálaí go ndearnadh an chartlann a íoslódáil go cam, agus tar éis roinnt iarrachtaí chaith sé earráid.

Déanaimid coigeartú ar mhéid na cartlainne... Agus – bua! 🙂 Tá an toradh san fhíseán.

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

Iarmhairtí agus imoibriú an fhorbróra

Ar an mbealach céanna, d'fhéadfadh hackers úsáid a bhaint as gné neamhchinnteach Brabhsálaí UC chun leabharlanna mailíseach a dháileadh agus a reáchtáil. Oibreoidh na leabharlanna seo i gcomhthéacs an bhrabhsálaí, mar sin gheobhaidh siad gach cead córais. Mar thoradh air sin, tá an cumas chun fuinneoga fioscaireachta a thaispeáint, chomh maith le rochtain ar chomhaid oibre an iora Síneach oráiste, lena n-áirítear logáil isteach, pasfhocail agus fianáin atá stóráilte sa bhunachar sonraí.

Chuaigh muid i dteagmháil le forbróirí Brabhsálaí UC agus chuireamar ar an eolas iad faoin bhfadhb a fuaireamar, rinneamar iarracht an leochaileacht agus an chontúirt a chur in iúl, ach níor phléigh siad rud ar bith linn. Idir an dá linn, lean an brabhsálaí ag taispeáint a ghné chontúirteach i radharc soiléir. Ach a luaithe a nochtamar sonraí na leochaileachta, níorbh fhéidir neamhaird a dhéanamh di mar a bhí roimhe seo. Bhí 27 Márta
scaoileadh leagan nua de Brabhsálaí UC 12.10.9.1193, a fuair rochtain ar an bhfreastalaí trí HTTPS: puds.ucweb.com/upgrade/index.xhtml.

Ina theannta sin, tar éis an “shocrú” agus go dtí an t-am seo a scríobh an t-alt seo, tháinig teachtaireacht earráide leis an téacs “Úps, chuaigh rud éigin mícheart” mar thoradh ar iarracht a dhéanamh PDF a oscailt i mbrabhsálaí! Ní dhearnadh iarratas chuig an bhfreastalaí nuair a bhíothas ag iarraidh PDF a oscailt, ach rinneadh iarratas nuair a seoladh an brabhsálaí, rud a thugann le tuiscint go bhféadfaí cód inrite a íoslódáil go leanúnach de shárú ar rialacha Google Play.

Foinse: will.com

Add a comment