UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

அறிமுகம்

மார்ச் இறுதியில் நாங்கள் தெரிவிக்கப்பட்டது, UC உலாவியில் சரிபார்க்கப்படாத குறியீட்டை ஏற்றுவதற்கும் இயக்குவதற்கும் மறைக்கப்பட்ட திறனை அவர்கள் கண்டுபிடித்தனர். இந்த பதிவிறக்கம் எவ்வாறு நிகழ்கிறது மற்றும் ஹேக்கர்கள் தங்கள் சொந்த நோக்கங்களுக்காக இதை எவ்வாறு பயன்படுத்தலாம் என்பதை இன்று விரிவாகப் பார்ப்போம்.

சில காலத்திற்கு முன்பு, UC உலாவி மிகவும் ஆக்ரோஷமாக விளம்பரப்படுத்தப்பட்டு விநியோகிக்கப்பட்டது: இது தீம்பொருளைப் பயன்படுத்தி பயனர்களின் சாதனங்களில் நிறுவப்பட்டது, வீடியோ கோப்புகள் என்ற போர்வையில் பல்வேறு தளங்களிலிருந்து விநியோகிக்கப்பட்டது (அதாவது, பயனர்கள் தாங்கள் பதிவிறக்குவதாக நினைத்தனர், எடுத்துக்காட்டாக, ஒரு ஆபாச வீடியோ, ஆனால் அதற்கு பதிலாக இந்த உலாவியில் APK கிடைத்தது), உலாவி காலாவதியானது, பாதிக்கப்படக்கூடியது மற்றும் அது போன்ற செய்திகளுடன் பயமுறுத்தும் பேனர்களைப் பயன்படுத்தியது. VK இல் அதிகாரப்பூர்வ UC உலாவி குழுவில் உள்ளது தீம், இதில் பயனர்கள் நியாயமற்ற விளம்பரங்களைப் பற்றி புகார் செய்யலாம், பல உதாரணங்கள் உள்ளன. 2016 இல் கூட இருந்தது வீடியோ விளம்பரம் ரஷ்ய மொழியில் (ஆம், விளம்பரத்தைத் தடுக்கும் உலாவிக்கான விளம்பரம்).

எழுதும் நேரத்தில், UC உலாவியில் Google Play இல் 500 நிறுவல்கள் உள்ளன. இது சுவாரஸ்யமாக உள்ளது - கூகுள் குரோம் மட்டுமே அதிகம் உள்ளது. மதிப்புரைகளில், கூகுள் ப்ளேயில் சில பயன்பாடுகளுக்கு விளம்பரம் மற்றும் வழிமாற்றுகள் பற்றிய பல புகார்களை நீங்கள் காணலாம். இதுவே எங்கள் ஆராய்ச்சிக்கான காரணம்: UC Browser ஏதாவது மோசமாகச் செய்கிறதா என்பதைப் பார்க்க முடிவு செய்தோம். அவர் செய்கிறார் என்று மாறியது!

பயன்பாட்டுக் குறியீட்டில், இயங்கக்கூடிய குறியீட்டைப் பதிவிறக்கி இயக்கும் திறன் கண்டறியப்பட்டது, விண்ணப்பங்களை வெளியிடுவதற்கான விதிகளுக்கு முரணானது Google Play இல். இயங்கக்கூடிய குறியீட்டைப் பதிவிறக்குவதுடன், UC உலாவி பாதுகாப்பற்ற முறையில் செய்கிறது, இது MitM தாக்குதலைத் தொடங்கப் பயன்படும். அப்படி ஒரு தாக்குதலை நடத்த முடியுமா என்று பார்ப்போம்.

ஆய்வின் போது Google Play இல் கிடைத்த UC உலாவியின் பதிப்பிற்கு கீழே எழுதப்பட்ட அனைத்தும் பொருத்தமானவை:

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

தாக்குதல் திசையன்

UC பிரவுசர் மேனிஃபெஸ்டில் நீங்கள் சுய விளக்கப் பெயருடன் ஒரு சேவையைக் காணலாம் 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 உலாவியின் இந்த அம்சத்தைப் பயன்படுத்த முடிவு செய்தோம்: APK இல் இல்லாத மற்றும் தேவைப்பட்டால் இணையத்திலிருந்து பதிவிறக்கும் சொந்த நூலகத்தைப் பயன்படுத்தி PDF ஐத் திறக்கும் திறன். கோட்பாட்டளவில், UC உலாவி பயனர் தொடர்பு இல்லாமல் எதையாவது பதிவிறக்கம் செய்ய வேண்டிய கட்டாயத்தில் உள்ளது என்பது கவனிக்கத்தக்கது - உலாவி தொடங்கப்பட்ட பிறகு செயல்படுத்தப்படும் கோரிக்கைக்கு நீங்கள் நன்கு வடிவமைக்கப்பட்ட பதிலை வழங்கினால். ஆனால் இதைச் செய்ய, சேவையகத்துடனான தொடர்புகளின் நெறிமுறையை இன்னும் விரிவாகப் படிக்க வேண்டும், எனவே இடைமறித்த பதிலைத் திருத்துவது மற்றும் PDF உடன் பணிபுரிய நூலகத்தை மாற்றுவது எளிதாக இருக்கும் என்று நாங்கள் முடிவு செய்தோம்.

எனவே, ஒரு பயனர் நேரடியாக உலாவியில் PDF ஐ திறக்க விரும்பினால், பின்வரும் கோரிக்கைகளை போக்குவரத்தில் காணலாம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

முதலில் ஒரு POST கோரிக்கை உள்ளது puds.ucweb.com/upgrade/index.xhtml, பிறகு
PDF மற்றும் அலுவலக வடிவங்களைப் பார்ப்பதற்கான நூலகத்துடன் கூடிய காப்பகம் பதிவிறக்கப்பட்டது. முதல் கோரிக்கையானது கணினியைப் பற்றிய தகவல்களை அனுப்புகிறது என்று கருதுவது தர்க்கரீதியானது (குறைந்தபட்சம் தேவையான நூலகத்தை வழங்குவதற்கான கட்டிடக்கலை), அதற்கு பதிலளிக்கும் விதமாக உலாவி பதிவிறக்கம் செய்ய வேண்டிய நூலகம் பற்றிய சில தகவல்களைப் பெறுகிறது: முகவரி மற்றும், ஒருவேளை , வேறு ஏதாவது. பிரச்சனை என்னவென்றால், இந்த கோரிக்கை குறியாக்கம் செய்யப்பட்டுள்ளது.

கோரிக்கை துண்டு

பதில் துண்டு

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

நூலகம் ஜிப் இல் தொகுக்கப்பட்டுள்ளது மற்றும் குறியாக்கம் செய்யப்படவில்லை.

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 என்பது முறையைப் போலவே மறைகுறியாக்கம் என்று பொருள் இறுதி அமைப்பு வகுப்பு 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);
}
}

மற்றும் வகுப்பு JNIC நூலகம், இதில் இவரது முறை அறிவிக்கப்பட்டுள்ளது 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. நாங்கள் அதை ஐடிஏவில் திறந்து பிழைகளுடன் கூடிய உரையாடல் பெட்டிகளைப் பெறுகிறோம். பிரச்சனை என்னவென்றால், பிரிவு தலைப்பு அட்டவணை தவறானது. பகுப்பாய்வை சிக்கலாக்கும் நோக்கத்துடன் இது செய்யப்படுகிறது.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

ஆனால் இது தேவையில்லை: ELF கோப்பை சரியாக ஏற்றி அதை பகுப்பாய்வு செய்ய, நிரல் தலைப்பு அட்டவணை போதுமானது. எனவே, தலைப்பில் உள்ள தொடர்புடைய புலங்களை பூஜ்ஜியமாக்குவதன் மூலம் பிரிவு அட்டவணையை வெறுமனே நீக்குகிறோம்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

ஐடிஏவில் கோப்பை மீண்டும் திறக்கவும்.

ஜாவா மெய்நிகர் இயந்திரத்தை நேட்டிவ் லைப்ரரியில் நேட்டிவ் என ஜாவா குறியீட்டில் அறிவிக்கப்பட்ட ஒரு முறை செயல்படுத்தப்படும் இடத்தில் சரியாகச் சொல்ல இரண்டு வழிகள் உள்ளன. முதலாவதாக, அதற்கு ஒரு இனம் பெயர் கொடுக்க வேண்டும் Java_package_name_ClassName_MethodName.

இரண்டாவது, நூலகத்தை ஏற்றும்போது அதை பதிவு செய்வது (செயல்பாட்டில் JNI_Onload)
செயல்பாட்டு அழைப்பைப் பயன்படுத்தி பதிவுசெய்தவர்கள்.

எங்கள் விஷயத்தில், முதல் முறையைப் பயன்படுத்தினால், பெயர் இப்படி இருக்க வேண்டும்: Java_com_taobao_wireless_security_adapter_JNICLibrary_doCommandNative.

ஏற்றுமதி செய்யப்பட்ட செயல்பாடுகளில் அத்தகைய செயல்பாடு எதுவும் இல்லை, அதாவது நீங்கள் அழைப்பைத் தேட வேண்டும் பதிவுசெய்தவர்கள்.
விழாவிற்கு செல்வோம் JNI_Onload மற்றும் நாம் இந்த படத்தை பார்க்கிறோம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

இங்கே என்ன நடந்து கொண்டிருக்கின்றது? முதல் பார்வையில், செயல்பாட்டின் தொடக்கமும் முடிவும் ARM கட்டமைப்பிற்கு பொதுவானவை. ஸ்டாக்கின் முதல் அறிவுறுத்தலானது, செயல்பாடு அதன் செயல்பாட்டில் பயன்படுத்தும் பதிவேடுகளின் உள்ளடக்கங்களை (இந்த வழக்கில், R0, R1 மற்றும் R2), அத்துடன் LR பதிவேட்டின் உள்ளடக்கங்களையும் சேமிக்கிறது, இதில் செயல்பாட்டிலிருந்து திரும்பும் முகவரியைக் கொண்டுள்ளது. . கடைசி அறிவுறுத்தல் சேமிக்கப்பட்ட பதிவேடுகளை மீட்டெடுக்கிறது, மேலும் திரும்பும் முகவரி உடனடியாக பிசி பதிவேட்டில் வைக்கப்படும் - இதனால் செயல்பாட்டிலிருந்து திரும்பும். ஆனால் நீங்கள் உற்று நோக்கினால், கடைசி அறிவுறுத்தல் அடுக்கில் சேமிக்கப்பட்ட திரும்பும் முகவரியை மாற்றுவதை நீங்கள் கவனிப்பீர்கள். பிறகு எப்படி இருக்கும் என்று கணக்கிடுவோம்
குறியீடு செயல்படுத்தல். ஒரு குறிப்பிட்ட முகவரி 1xB0 R130 இல் ஏற்றப்பட்டது, அதிலிருந்து 5 கழிக்கப்படுகிறது, பின்னர் அது R0 க்கு மாற்றப்பட்டு 0x10 அதில் சேர்க்கப்படுகிறது. இது 0xB13B ஆக மாறும். எனவே, ஐடிஏ கடைசி அறிவுறுத்தல் ஒரு சாதாரண செயல்பாடு திரும்பும் என்று நினைக்கிறது, ஆனால் உண்மையில் அது கணக்கிடப்பட்ட முகவரி 0xB13B க்கு செல்கிறது.

ARM செயலிகளில் இரண்டு முறைகள் மற்றும் இரண்டு வழிமுறைகள் உள்ளன என்பதை இங்கே நினைவுபடுத்துவது மதிப்பு: ARM மற்றும் Thumb. முகவரியின் குறைந்த முக்கியத்துவம் வாய்ந்த பிட் எந்த அறிவுறுத்தல் தொகுப்பு பயன்படுத்தப்படுகிறது என்பதை செயலிக்கு தெரிவிக்கிறது. அதாவது, முகவரி உண்மையில் 0xB13A ஆகும், மேலும் குறிப்பிடத்தக்க பிட்டில் ஒன்று கட்டைவிரல் பயன்முறையைக் குறிக்கிறது.

இந்த நூலகத்தில் உள்ள ஒவ்வொரு செயல்பாட்டின் தொடக்கத்திலும் இதேபோன்ற "அடாப்டர்" சேர்க்கப்பட்டுள்ளது
குப்பை குறியீடு. நாங்கள் அவற்றை மேலும் விரிவாகக் கூற மாட்டோம் - நாங்கள் நினைவில் கொள்கிறோம்
ஏறக்குறைய அனைத்து செயல்பாடுகளின் உண்மையான தொடக்கமும் சிறிது தொலைவில் உள்ளது.

குறியீடு வெளிப்படையாக 0xB13A க்கு தாவாததால், குறியீடு இந்த இடத்தில் இருப்பதை IDA அங்கீகரிக்கவில்லை. அதே காரணத்திற்காக, நூலகத்தில் உள்ள பெரும்பாலான குறியீட்டை இது குறியீடாக அங்கீகரிக்கவில்லை, இது பகுப்பாய்வைச் சற்று கடினமாக்குகிறது. இது குறியீடு என்று ஐடிஏவிடம் சொல்கிறோம், இதுதான் நடக்கும்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

அட்டவணை தெளிவாக 0xB144 இல் தொடங்குகிறது. sub_494C இல் என்ன இருக்கிறது?

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

LR பதிவேட்டில் இந்த செயல்பாட்டை அழைக்கும் போது, ​​முன்னர் குறிப்பிடப்பட்ட அட்டவணையின் (0xB144) முகவரியைப் பெறுகிறோம். இந்த அட்டவணையில் R0 - குறியீட்டில். அதாவது, மதிப்பு அட்டவணையில் இருந்து எடுக்கப்பட்டது, LR இல் சேர்க்கப்பட்டது மற்றும் முடிவு
செல்ல வேண்டிய முகவரி. அதைக் கணக்கிட முயற்சிப்போம்: 0xB144 + [0xB144 + 8* 4] = 0xB144 + 0x120 = 0xB264. நாங்கள் பெறப்பட்ட முகவரிக்குச் சென்று இரண்டு பயனுள்ள வழிமுறைகளைப் பார்த்து மீண்டும் 0xB140 க்குச் செல்கிறோம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

இப்போது அட்டவணையில் இருந்து குறியீட்டு 0x20 உடன் ஆஃப்செட்டில் ஒரு மாற்றம் இருக்கும்.

அட்டவணையின் அளவைப் பொறுத்து, குறியீட்டில் இதுபோன்ற பல மாற்றங்கள் இருக்கும். முகவரிகளை கைமுறையாகக் கணக்கிடாமல், இதை எப்படியாவது தானாகவே சமாளிக்க முடியுமா என்ற கேள்வி எழுகிறது. ஸ்கிரிப்டுகள் மற்றும் ஐடிஏவில் குறியீட்டை இணைக்கும் திறன் ஆகியவை எங்கள் உதவிக்கு வருகின்றன:

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 க்கு மாறுவதைப் பார்க்கவும்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

ஐடிஏ மீண்டும் இந்தப் பகுதியை ஒரு குறியீடாக அங்கீகரிக்கவில்லை. நாங்கள் அவளுக்கு உதவுகிறோம், அங்கு மற்றொரு வடிவமைப்பைப் பார்க்கிறோம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

BLX க்குப் பிறகு உள்ள வழிமுறைகள் அதிக அர்த்தமுள்ளதாகத் தெரியவில்லை, இது ஒருவித இடப்பெயர்ச்சி போன்றது. sub_4964 ஐப் பார்ப்போம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

உண்மையில், இங்கே LR இல் உள்ள முகவரியில் ஒரு dword எடுக்கப்பட்டு, இந்த முகவரியில் சேர்க்கப்பட்டு, அதன் விளைவாக வரும் முகவரியில் உள்ள மதிப்பு எடுக்கப்பட்டு அடுக்கில் வைக்கப்படுகிறது. மேலும், 4 ஆனது LR இல் சேர்க்கப்பட்டது, அதனால் செயல்பாட்டிலிருந்து திரும்பிய பிறகு, இதே ஆஃப்செட் தவிர்க்கப்படும். அதன் பிறகு POP {R1} கட்டளையானது ஸ்டாக்கிலிருந்து பெறப்பட்ட மதிப்பை எடுக்கும். முகவரி 0xB4BA + 0xEA = 0xB5A4 இல் உள்ளதைப் பார்த்தால், முகவரி அட்டவணையைப் போன்ற ஒன்றைக் காண்பீர்கள்:

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 - மற்றும் ஸ்கிரிப்டை இயக்கவும்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

ஏற்கனவே குறிப்பிடப்பட்ட கட்டமைப்புகளுக்கு கூடுதலாக, குறியீடு பின்வருவனவற்றையும் கொண்டுள்ளது:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

முந்தைய வழக்கைப் போலவே, BLX அறிவுறுத்தலுக்குப் பிறகு ஒரு ஆஃப்செட் உள்ளது:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

எல்ஆரில் இருந்து முகவரிக்கு ஆஃப்செட்டை எடுத்து, அதை எல்ஆரில் சேர்த்துவிட்டு அங்கு செல்கிறோம். 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"

ஸ்கிரிப்ட் செயல்பாட்டின் முடிவு:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

செயல்பாட்டில் அனைத்தும் இணைக்கப்பட்டவுடன், நீங்கள் IDA ஐ அதன் உண்மையான தொடக்கத்திற்கு சுட்டிக்காட்டலாம். இது அனைத்து செயல்பாட்டுக் குறியீட்டையும் ஒன்றாக இணைக்கும், மேலும் அதை HexRays ஐப் பயன்படுத்தி சிதைக்கலாம்.

டிகோடிங் சரங்கள்

நூலகத்தில் உள்ள இயந்திரக் குறியீட்டின் தெளிவின்மையை சமாளிக்க கற்றுக்கொண்டோம் libsgmainso-6.4.36.so 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);

செயல்பாட்டில் துணை_73E24 வகுப்பின் பெயர் தெளிவாக மறைகுறியாக்கப்படுகிறது. இந்தச் செயல்பாட்டின் அளவுருக்களாக, குறியாக்கம் செய்யப்பட்ட தரவுகளைப் போன்ற தரவுகளுக்கான ஒரு சுட்டிக்காட்டி, ஒரு குறிப்பிட்ட இடையக மற்றும் எண் அனுப்பப்படும். வெளிப்படையாக, செயல்பாட்டை அழைத்த பிறகு, இடையகத்தில் மறைகுறியாக்கப்பட்ட கோடு இருக்கும், ஏனெனில் அது செயல்பாட்டிற்கு அனுப்பப்படுகிறது. FindClass, இது வகுப்பின் பெயரை இரண்டாவது அளவுருவாக எடுத்துக்கொள்கிறது. எனவே, எண் என்பது இடையகத்தின் அளவு அல்லது கோட்டின் நீளம். வகுப்பின் பெயரைப் புரிந்துகொள்ள முயற்சிப்போம், நாம் சரியான திசையில் செல்கிறோமா என்பதை அது சொல்ல வேண்டும். என்ன நடக்கிறது என்பதை விரிவாகப் பார்ப்போம் துணை_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;
}

செயல்பாடு துணை_7AF78 குறிப்பிட்ட அளவிலான பைட் வரிசைகளுக்கான கொள்கலனின் உதாரணத்தை உருவாக்குகிறது (இந்த கொள்கலன்களில் நாங்கள் விரிவாக இருக்க மாட்டோம்). அத்தகைய இரண்டு கொள்கலன்கள் இங்கே உருவாக்கப்பட்டுள்ளன: ஒன்று வரியைக் கொண்டுள்ளது "DcO/lcK+h?m3c*q@" (இது ஒரு திறவுகோல் என்று யூகிக்க எளிதானது), மற்றொன்று மறைகுறியாக்கப்பட்ட தரவைக் கொண்டுள்ளது. அடுத்து, இரண்டு பொருட்களும் ஒரு குறிப்பிட்ட கட்டமைப்பில் வைக்கப்படுகின்றன, இது செயல்பாட்டிற்கு அனுப்பப்படுகிறது துணை_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: செயல்பாட்டிற்குப் பார்க்கவும் துணை_6364C முந்தைய செயல்பாட்டில் சேர்க்கப்பட்ட கட்டமைப்பிலிருந்து அளவுருக்கள் அனுப்பப்படுகின்றன, அதாவது விசை மற்றும் மறைகுறியாக்கப்பட்ட தரவு. கூர்ந்து கவனித்தால் துணை_6364C, அதில் உள்ள RC4 அல்காரிதத்தை நீங்கள் அடையாளம் காணலாம்.

எங்களிடம் ஒரு அல்காரிதம் மற்றும் விசை உள்ளது. வகுப்பின் பெயரைப் புரிந்துகொள்ள முயற்சிப்போம். என்ன நடந்தது என்பது இங்கே: com/taobao/wireless/security/adapter/JNICLibrary. நன்று! நாங்கள் சரியான பாதையில் செல்கிறோம்.

கட்டளை மரம்

இப்போது நாம் ஒரு சவாலைக் கண்டுபிடிக்க வேண்டும் பதிவுசெய்தவர்கள், இது செயல்பாட்டிற்கு நம்மைச் சுட்டிக்காட்டும் doCommandNative. இருந்து அழைக்கப்படும் செயல்பாடுகளை பார்க்கலாம் JNI_Onload, மற்றும் நாம் அதை கண்டுபிடிக்கிறோம் துணை_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 ஐக் குறிக்கலாம்), கட்டளை மரம் கட்டப்பட்டுள்ளது.

இந்த மாதிரி ஏதாவது:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

மரம் மாறும் வகையில் நிரப்பப்பட்டுள்ளது JNI_Onload.
மரத்தில் உள்ள பாதையை மூன்று எண்கள் குறியாக்கம் செய்கின்றன. மரத்தின் ஒவ்வொரு இலையிலும் தொடர்புடைய செயல்பாட்டின் பாக் செய்யப்பட்ட முகவரி உள்ளது. திறவுகோல் பெற்றோர் முனையில் உள்ளது. பயன்படுத்தப்படும் அனைத்து கட்டமைப்புகளையும் நீங்கள் புரிந்து கொண்டால், மரத்தில் நமக்குத் தேவையான செயல்பாடு சேர்க்கப்படும் குறியீட்டில் இடத்தைக் கண்டுபிடிப்பது கடினம் அல்ல (ஏற்கனவே பெரிய கட்டுரையை வீங்காமல் இருக்க நாங்கள் அவற்றை விவரிக்கவில்லை).

மேலும் தெளிவின்மை

போக்குவரத்தை மறைகுறியாக்க வேண்டிய செயல்பாட்டின் முகவரியைப் பெற்றோம்: 0x5F1AC. ஆனால் மகிழ்ச்சியடைவது மிக விரைவில்: UC உலாவியின் டெவலப்பர்கள் எங்களுக்கு மற்றொரு ஆச்சரியத்தைத் தயாரித்துள்ளனர்.

ஜாவா குறியீட்டில் உருவாக்கப்பட்ட வரிசையிலிருந்து அளவுருக்களைப் பெற்ற பிறகு, நாம் பெறுகிறோம்
0x4D070 முகவரியில் உள்ள செயல்பாட்டிற்கு. இங்கே மற்றொரு வகையான குறியீட்டு குழப்பம் நமக்குக் காத்திருக்கிறது.

R7 மற்றும் R4 இல் இரண்டு குறியீடுகளை வைக்கிறோம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

முதல் குறியீட்டை R11க்கு மாற்றுகிறோம்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

அட்டவணையில் இருந்து முகவரியைப் பெற, குறியீட்டைப் பயன்படுத்தவும்:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

முதல் முகவரிக்குச் சென்ற பிறகு, இரண்டாவது குறியீடு பயன்படுத்தப்படுகிறது, இது R4 இல் உள்ளது. அட்டவணையில் 230 கூறுகள் உள்ளன.

அதற்கு என்ன செய்வது? இது ஒரு ஸ்விட்ச் என்று நீங்கள் ஐடிஏ சொல்லலாம்: திருத்து -> மற்றவை -> சுவிட்ச் ஐடியமைக் குறிப்பிடவும்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

இதன் விளைவாக வரும் குறியீடு பயங்கரமானது. ஆனால், அதன் காடு வழியாகச் செல்லும்போது, ​​எங்களுக்கு ஏற்கனவே பழக்கமான ஒரு செயல்பாட்டிற்கான அழைப்பை நீங்கள் கவனிக்கலாம் துணை_6115C:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

3 இல் RC4 அல்காரிதத்தைப் பயன்படுத்தி மறைகுறியாக்கம் செய்யப்பட்ட ஒரு சுவிட்ச் இருந்தது. இந்த வழக்கில், செயல்பாட்டிற்கு அனுப்பப்பட்ட அமைப்பு அனுப்பப்பட்ட அளவுருக்களிலிருந்து நிரப்பப்படுகிறது doCommandNative. அங்கே என்ன இருந்தது என்பதை நினைவில் கொள்வோம் மேஜிக் இன்ட் மதிப்புடன் 16. தொடர்புடைய வழக்கைப் பார்க்கிறோம் - மேலும் பல மாற்றங்களுக்குப் பிறகு, அல்காரிதம் அடையாளம் காணக்கூடிய குறியீட்டைக் காண்கிறோம்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

இது AES!

அல்காரிதம் உள்ளது, அதன் அளவுருக்களைப் பெறுவதே எஞ்சியிருக்கும்: பயன்முறை, விசை மற்றும், ஒருவேளை, துவக்க திசையன் (அதன் இருப்பு AES அல்காரிதத்தின் இயக்க முறைமையைப் பொறுத்தது). செயல்பாடு அழைப்புக்கு முன் அவர்களுடன் கூடிய அமைப்பு எங்காவது உருவாக்கப்பட வேண்டும் துணை_6115C, ஆனால் குறியீட்டின் இந்த பகுதி குறிப்பாக நன்கு தெளிவற்றதாக உள்ளது, எனவே குறியீட்டை ஒட்டுவதற்கான யோசனை எழுகிறது, இதனால் மறைகுறியாக்க செயல்பாட்டின் அனைத்து அளவுருக்களும் ஒரு கோப்பில் கொட்டப்படும்.

இணைப்பு

அசெம்பிளி மொழியில் அனைத்து பேட்ச் குறியீட்டையும் கைமுறையாக எழுதாமல் இருக்க, நீங்கள் ஆண்ட்ராய்டு ஸ்டுடியோவைத் தொடங்கலாம், எங்கள் டிக்ரிப்ஷன் செயல்பாட்டின் அதே உள்ளீட்டு அளவுருக்களைப் பெற்று ஒரு கோப்பில் எழுதும் செயல்பாட்டை எழுதலாம், பின்னர் கம்பைலர் செய்யும் குறியீட்டை நகலெடுத்து ஒட்டவும். உருவாக்க.

UC பிரவுசர் குழுவைச் சேர்ந்த எங்கள் நண்பர்களும் குறியீட்டைச் சேர்ப்பதற்கான வசதியைக் கவனித்துக்கொண்டனர். ஒவ்வொரு செயல்பாட்டின் தொடக்கத்திலும் எங்களிடம் குப்பை குறியீடு உள்ளது என்பதை நினைவில் கொள்வோம், அதை எளிதாக வேறு எதையும் மாற்றலாம். மிகவும் வசதியானது 🙂 இருப்பினும், இலக்கு செயல்பாட்டின் தொடக்கத்தில் ஒரு கோப்பில் அனைத்து அளவுருக்களையும் சேமிக்கும் குறியீட்டிற்கு போதுமான இடம் இல்லை. நான் அதை பகுதிகளாகப் பிரித்து, அண்டை செயல்பாடுகளிலிருந்து குப்பைத் தொகுதிகளைப் பயன்படுத்த வேண்டியிருந்தது. மொத்தம் நான்கு பாகங்கள் இருந்தன.

முதல் பகுதி:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

ARM கட்டமைப்பில், முதல் நான்கு செயல்பாட்டு அளவுருக்கள் R0-R3 பதிவேடுகள் வழியாக அனுப்பப்படுகின்றன, மீதமுள்ளவை, ஏதேனும் இருந்தால், ஸ்டேக் வழியாக அனுப்பப்படும். LR பதிவேட்டில் திரும்பும் முகவரி உள்ளது. இவை அனைத்தும் சேமிக்கப்பட வேண்டும், இதன் மூலம் அதன் அளவுருக்களை நாங்கள் டம்ப் செய்த பிறகு செயல்பாடு செயல்பட முடியும். செயல்பாட்டில் நாம் பயன்படுத்தும் அனைத்து பதிவுகளையும் சேமிக்க வேண்டும், எனவே நாங்கள் PUSH.W {R0-R10,LR} செய்கிறோம். R7 இல், ஸ்டேக் வழியாக செயல்பாட்டிற்கு அனுப்பப்பட்ட அளவுருக்களின் பட்டியலின் முகவரியைப் பெறுகிறோம்.

செயல்பாட்டைப் பயன்படுத்துதல் fopen கோப்பை திறப்போம் /data/local/tmp/aes "ab" முறையில்
அதாவது கூட்டலுக்கு. R0 இல் கோப்பு பெயரின் முகவரியை ஏற்றுவோம், R1 இல் - பயன்முறையைக் குறிக்கும் வரியின் முகவரி. இங்கே குப்பை குறியீடு முடிவடைகிறது, எனவே நாம் அடுத்த செயல்பாட்டிற்கு செல்கிறோம். இது தொடர்ந்து வேலை செய்ய, தொடக்கத்தில் செயல்பாட்டின் உண்மையான குறியீட்டிற்கு மாற்றத்தை வைக்கிறோம், குப்பைகளைத் தவிர்த்து, குப்பைக்கு பதிலாக இணைப்பின் தொடர்ச்சியைச் சேர்க்கிறோம்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

அழைப்பு fopen.

செயல்பாட்டின் முதல் மூன்று அளவுருக்கள் aes வகை வேண்டும் எண்ணாக. தொடக்கத்தில் பதிவேடுகளை அடுக்கில் சேமித்ததால், செயல்பாட்டை எளிமையாக அனுப்பலாம் fwrite அடுக்கில் அவர்களின் முகவரிகள்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

அடுத்து எங்களிடம் மூன்று கட்டமைப்புகள் உள்ளன, அவை தரவு அளவு மற்றும் விசைக்கான தரவுக்கான சுட்டி, துவக்க திசையன் மற்றும் மறைகுறியாக்கப்பட்ட தரவு ஆகியவற்றைக் கொண்டுள்ளன.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

முடிவில், கோப்பை மூடி, பதிவேடுகளை மீட்டமைத்து உண்மையான செயல்பாட்டிற்கு கட்டுப்பாட்டை மாற்றவும் aes.

இணைக்கப்பட்ட நூலகத்துடன் APKஐச் சேகரித்து, அதில் கையொப்பமிட்டு, சாதனம்/முன்மாதிரியில் பதிவேற்றி, அதைத் தொடங்குவோம். எங்கள் டம்ப் உருவாக்கப்படுவதையும், நிறைய தரவுகள் எழுதப்படுவதையும் நாங்கள் காண்கிறோம். உலாவியானது போக்குவரத்திற்கு மட்டும் குறியாக்கத்தைப் பயன்படுத்துகிறது, மேலும் அனைத்து குறியாக்கமும் கேள்விக்குரிய செயல்பாட்டின் மூலம் செல்கிறது. ஆனால் சில காரணங்களால் தேவையான தரவு இல்லை, மேலும் தேவையான கோரிக்கை போக்குவரத்தில் தெரியவில்லை. UC உலாவி தேவையான கோரிக்கையை உருவாக்கும் வரை காத்திருக்காமல் இருக்க, முன்னர் பெறப்பட்ட சேவையகத்திலிருந்து மறைகுறியாக்கப்பட்ட பதிலை எடுத்து, விண்ணப்பத்தை மீண்டும் இணைக்கலாம்: முக்கிய செயல்பாட்டின் 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 இல் அந்த பெயரில் ஒரு கோப்புறையை உருவாக்கி, அதில் அணில் உலாவி சான்றிதழை சேர்க்கவும்.

நாங்கள் அசெம்பிள் செய்கிறோம், கையொப்பமிடுகிறோம், நிறுவுகிறோம், துவக்குகிறோம். பிங்கோ! எங்களிடம் சாவி இருக்கிறது!

MitM

விசைக்கு சமமான விசையையும் துவக்க திசையன்களையும் பெற்றோம். சிபிசி பயன்முறையில் சர்வர் பதிலை மறைகுறியாக்க முயற்சிப்போம்.

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

MD5, “extract_unzipsize” மற்றும் எண்ணைப் போன்ற காப்பக URL ஐக் காண்கிறோம். நாங்கள் சரிபார்க்கிறோம்: காப்பகத்தின் MD5 ஒன்றுதான், தொகுக்கப்படாத நூலகத்தின் அளவு ஒன்றுதான். இந்த லைப்ரரியை பேட்ச் செய்து பிரவுசரில் கொடுக்க முயற்சிக்கிறோம். எங்கள் பேட்ச் செய்யப்பட்ட லைப்ரரி ஏற்றப்பட்டதைக் காட்ட, “PWNED!” என்ற உரையுடன் ஒரு எஸ்எம்எஸ் உருவாக்கும் நோக்கத்தைத் தொடங்குவோம். சேவையகத்திலிருந்து இரண்டு பதில்களை மாற்றுவோம்: puds.ucweb.com/upgrade/index.xhtml மற்றும் காப்பகத்தை பதிவிறக்கம் செய்ய. முதலில் நாம் MD5 ஐ மாற்றுகிறோம் (திறந்த பிறகு அளவு மாறாது), இரண்டாவதாக நாம் பேட்ச் செய்யப்பட்ட நூலகத்துடன் காப்பகத்தை தருகிறோம்.

உலாவி காப்பகத்தை பல முறை பதிவிறக்க முயற்சிக்கிறது, அதன் பிறகு அது ஒரு பிழையை அளிக்கிறது. வெளிப்படையாக ஏதாவது
அவருக்கு பிடிக்காது. இந்த இருண்ட வடிவமைப்பை பகுப்பாய்வு செய்ததன் விளைவாக, சேவையகம் காப்பகத்தின் அளவையும் அனுப்புகிறது:

UC உலாவியில் பாதிப்புகளைத் தேடுகிறது

இது LEB128 இல் குறியிடப்பட்டுள்ளது. இணைப்புக்குப் பிறகு, நூலகத்துடன் கூடிய காப்பகத்தின் அளவு சிறிது மாறியது, எனவே காப்பகம் வளைந்த முறையில் பதிவிறக்கம் செய்யப்பட்டதாக உலாவி கருதியது, மேலும் பல முயற்சிகளுக்குப் பிறகு அது பிழையை ஏற்படுத்தியது.

காப்பகத்தின் அளவை நாங்கள் சரிசெய்கிறோம் ... மேலும் - வெற்றி! 🙂 முடிவு வீடியோவில் உள்ளது.

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

விளைவுகள் மற்றும் டெவலப்பர் எதிர்வினை

அதே வழியில், ஹேக்கர்கள் UC உலாவியின் பாதுகாப்பற்ற அம்சத்தைப் பயன்படுத்தி தீங்கிழைக்கும் நூலகங்களை விநியோகிக்கவும் இயக்கவும் முடியும். இந்த நூலகங்கள் உலாவியின் சூழலில் செயல்படும், எனவே அவை அதன் அனைத்து கணினி அனுமதிகளையும் பெறும். இதன் விளைவாக, ஃபிஷிங் சாளரங்களைக் காண்பிக்கும் திறன், அத்துடன் தரவுத்தளத்தில் சேமிக்கப்பட்ட உள்நுழைவுகள், கடவுச்சொற்கள் மற்றும் குக்கீகள் உள்ளிட்ட ஆரஞ்சு சீன அணில் வேலை செய்யும் கோப்புகளுக்கான அணுகல்.

UC உலாவியின் டெவலப்பர்களைத் தொடர்புகொண்டு, நாங்கள் கண்டறிந்த சிக்கலைப் பற்றி அவர்களிடம் தெரிவித்தோம், பாதிப்பு மற்றும் அதன் ஆபத்தை சுட்டிக்காட்ட முயற்சித்தோம், ஆனால் அவர்கள் எங்களுடன் எதையும் விவாதிக்கவில்லை. இதற்கிடையில், உலாவி அதன் ஆபத்தான அம்சத்தை வெற்றுப் பார்வையில் தொடர்ந்து வெளிப்படுத்தியது. ஆனால் பாதிப்பு குறித்த விவரங்களை நாங்கள் வெளிப்படுத்தியவுடன், முன்பு போல் அதை புறக்கணிக்க முடியாது. மார்ச் 27 இருந்தது
UC உலாவியின் புதிய பதிப்பு 12.10.9.1193 வெளியிடப்பட்டது, இது HTTPS வழியாக சேவையகத்தை அணுகியது: puds.ucweb.com/upgrade/index.xhtml.

கூடுதலாக, “சரிசெய்தல்”க்குப் பிறகு மற்றும் இந்தக் கட்டுரையை எழுதும் நேரம் வரை, உலாவியில் PDFஐத் திறக்க முயற்சித்ததால், “அச்சச்சோ, ஏதோ தவறாகிவிட்டது!” என்ற உரையுடன் பிழைச் செய்தி வந்தது. PDF ஐத் திறக்க முயற்சிக்கும்போது சேவையகத்திற்கு கோரிக்கை விடுக்கப்படவில்லை, ஆனால் உலாவி தொடங்கப்பட்டபோது ஒரு கோரிக்கை செய்யப்பட்டது, இது Google Play விதிகளை மீறி இயங்கக்கூடிய குறியீட்டைப் பதிவிறக்குவதற்கான தொடர்ச்சியான திறனைக் குறிக்கிறது.

ஆதாரம்: www.habr.com

கருத்தைச் சேர்