├── README.md └── app └── src └── main ├── AndroidManifest.xml ├── assets └── xposed_init ├── java └── com │ └── unexpected │ └── capture │ └── uc │ ├── IniFile.java │ └── MainHook.java └── res └── values ├── arrays.xml └── strings.xml /README.md: -------------------------------------------------------------------------------- 1 | # UCProxyCapture 2 | UC 浏览器代理抓取 3 | 4 | # 简介 5 | UC 浏览器自启动后会抓取已开启的免流代理信息 6 | 7 | # 文件路径 8 | - /storage/emulated/0/UCDownloads 9 | - /storage/emulated/0/Download/UCDownloads 10 | - /storage/emulated/0/Android/data/包名/UCDownloads 11 | 12 | # 支持浏览器的版本 13 | UC浏览器: 14 | - 16.2.7.1278 15 | 16 | UC浏览器极速版: 17 | - 15.5.2.1242(仅电信) 18 | 19 | # 使用教程 20 | - 1.在 Xposed 框架找到模块并开启,打开模块作用域设置,勾选“UC 浏览器”。 21 | - 2.打开“UC 浏览器”,打开设置→高级设置→浏览器专享流量,填写你的手机号,并点击开启 22 | - 3.打开“文件管理”,打开配置保存路径: 可以看到 xxx.ini 文件,那个就是代理信息文件 23 | 24 | **注意:** 25 | - 现在联通也是动态生成的验证 26 | - 电信代理抓取到也没什么用 27 | - 如果抓取到的配置不会使用不要问我!!! 28 | 29 | # 停止维护 30 | 不再对这个项目进行更新 31 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 19 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | com.unexpected.capture.uc.MainHook 2 | -------------------------------------------------------------------------------- /app/src/main/java/com/unexpected/capture/uc/IniFile.java: -------------------------------------------------------------------------------- 1 | package com.unexpected.capture.uc; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import de.robv.android.xposed.XposedBridge; 6 | import de.robv.android.xposed.XposedHelpers; 7 | import java.io.BufferedWriter; 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.OutputStream; 12 | import java.io.OutputStreamWriter; 13 | import java.util.Enumeration; 14 | import java.util.Properties; 15 | 16 | 17 | public class IniFile { 18 | private final Properties mProperties = new Properties(); 19 | private final File mFile; 20 | 21 | public IniFile(@NonNull File file) { 22 | mFile = file; 23 | } 24 | 25 | @Nullable 26 | public Object set(@NonNull String key, @NonNull String value) { 27 | return mProperties.setProperty(key, value); 28 | } 29 | 30 | public boolean write() { 31 | FileOutputStream fos = null; 32 | try { 33 | fos = new FileOutputStream(mFile); 34 | store(mProperties, fos, null); 35 | return true; 36 | } catch(IOException e) { 37 | XposedBridge.log("Failed to write .ini file " + mFile + " error: " + e); 38 | } finally { 39 | if(fos != null) { 40 | try { 41 | fos.close(); 42 | } catch(IOException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | } 47 | return false; 48 | } 49 | 50 | public static void store(@NonNull Properties properties, @NonNull OutputStream out, @Nullable String comments) throws IOException { 51 | store0(properties, 52 | new BufferedWriter(new OutputStreamWriter(out, "8859_1")), 53 | comments, 54 | true); 55 | } 56 | 57 | private static void store0(@NonNull Properties properties, @NonNull BufferedWriter bw, @Nullable String comments, boolean escUnicode) throws IOException { 58 | if(comments != null) { 59 | XposedHelpers.callStaticMethod(Properties.class, "writeComments", bw, comments); 60 | } 61 | //bw.write("#" + new Date().toString()); 62 | //bw.newLine(); 63 | synchronized(properties) { 64 | for(Enumeration e = properties.keys(); e.hasMoreElements();) { 65 | String key = (String) e.nextElement(); 66 | String val = (String) properties.get(key); 67 | key = (String) XposedHelpers.callMethod(properties, "saveConvert", key, true, escUnicode); 68 | /* No need to escape embedded and trailing spaces for value, hence 69 | * pass false to flag. 70 | */ 71 | val = (String) XposedHelpers.callMethod(properties, "saveConvert", val, false, escUnicode); 72 | bw.write(key + "=" + val); 73 | bw.newLine(); 74 | } 75 | } 76 | bw.flush(); 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/unexpected/capture/uc/MainHook.java: -------------------------------------------------------------------------------- 1 | package com.unexpected.capture.uc; 2 | 3 | import android.util.Base64; 4 | import de.robv.android.xposed.IXposedHookLoadPackage; 5 | import de.robv.android.xposed.XC_MethodHook; 6 | import de.robv.android.xposed.XposedHelpers; 7 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 8 | import java.io.File; 9 | import java.net.Inet4Address; 10 | import java.net.InetAddress; 11 | import java.net.NetworkInterface; 12 | import java.util.Enumeration; 13 | import java.util.Locale; 14 | 15 | 16 | public class MainHook implements IXposedHookLoadPackage { 17 | public static final String PACKAGE_NAME = "com.UCMobile"; 18 | 19 | @Override 20 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 21 | if(PACKAGE_NAME.contains(lpparam.packageName)) { 22 | 23 | XposedHelpers.findAndHookConstructor("com.uc.browser.business.freeflow.a.b.b", 24 | lpparam.classLoader, byte[].class, new XC_MethodHook(){ 25 | @Override 26 | protected void afterHookedMethod(final XC_MethodHook.MethodHookParam param) throws Throwable { 27 | new Thread(new Runnable(){ 28 | @Override 29 | public void run() { 30 | Object pXP = XposedHelpers.getObjectField(param.thisObject, "pXP"); 31 | Object aVar = null; 32 | boolean b = pXP != null && (aVar = XposedHelpers.getObjectField(pXP, "qat")) != null; 33 | IniFile file = new IniFile(getFile("telecom")); 34 | long millis = System.currentTimeMillis(); 35 | file.set("time", "" + millis); 36 | file.set("date", String.format(Locale.ENGLISH, "%tF %tT", millis, millis)); 37 | if(b) { 38 | file.set("server", (String) XposedHelpers.callMethod(aVar, "getDomain")); 39 | file.set("port", (String) XposedHelpers.callMethod(aVar, "duH")); 40 | file.set("uid", (String) XposedHelpers.callMethod(pXP, "getOrderId")); 41 | file.set("token", (String) XposedHelpers.callMethod(aVar, "duI")); 42 | } else { 43 | file.set("server", ""); 44 | file.set("port", ""); 45 | file.set("uid", ""); 46 | file.set("token", ""); 47 | } 48 | file.write(); 49 | } 50 | }).start(); 51 | } 52 | }); 53 | 54 | XposedHelpers.findAndHookConstructor("com.uc.browser.business.freeflow.a.b.e", 55 | lpparam.classLoader, byte[].class, new XC_MethodHook(){ 56 | @Override 57 | protected void afterHookedMethod(final XC_MethodHook.MethodHookParam param) throws Throwable { 58 | new Thread(new Runnable(){ 59 | @Override 60 | public void run() { 61 | Object pXZ = XposedHelpers.getObjectField(param.thisObject, "pXZ"); 62 | IniFile file = new IniFile(getFile("unicom")); 63 | long millis = System.currentTimeMillis(); 64 | file.set("time", "" + millis); 65 | file.set("date", String.format(Locale.ENGLISH, "%tF %tT", millis, millis)); 66 | if(pXZ != null) { 67 | file.set("server", (String) XposedHelpers.callMethod(pXZ, "getIp")); 68 | file.set("port", String.valueOf(XposedHelpers.getIntField(pXZ, "port"))); 69 | String account = "uc".concat(getIp()); 70 | String password = (String) XposedHelpers.callMethod(pXZ, "getPassword"); 71 | file.set("account", account); 72 | file.set("password", password); 73 | file.set("base64", Base64.encodeToString(account.concat(":").concat(password).getBytes(), Base64.NO_WRAP)); 74 | } else { 75 | file.set("server", ""); 76 | file.set("port", ""); 77 | file.set("account", ""); 78 | file.set("password", ""); 79 | file.set("base64", ""); 80 | } 81 | file.write(); 82 | } 83 | }).start(); 84 | } 85 | }); 86 | } 87 | } 88 | 89 | public static File getFile(String fileName) { 90 | return new File("/storage/emulated/0/UCDownloads", fileName.concat(".ini")); 91 | } 92 | 93 | /*public static String getHost(String str) { 94 | if(!StringUtils.isEmpty(str)){ 95 | if(!str.contains("://")){ 96 | str="http://".concat(str); 97 | } 98 | try { 99 | return new URL(str).getHost(); 100 | } catch(Throwable ignore) { 101 | } 102 | } 103 | return ""; 104 | }*/ 105 | 106 | public static String getIp() { 107 | try { 108 | Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); 109 | while(networkInterfaces != null && networkInterfaces.hasMoreElements()) { 110 | NetworkInterface nextElement = networkInterfaces.nextElement(); 111 | Enumeration inetAddresses; 112 | if(nextElement != null && (inetAddresses = nextElement.getInetAddresses()) != null) { 113 | while(inetAddresses.hasMoreElements()) { 114 | InetAddress nextElement2 = inetAddresses.nextElement(); 115 | if(nextElement2 != null && !nextElement2.isLoopbackAddress() && nextElement2 instanceof Inet4Address) { 116 | return nextElement2.getHostAddress(); 117 | } 118 | } 119 | } 120 | } 121 | } catch(Throwable ignore) { 122 | } 123 | return "10.1.10.1"; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.UCMobile 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | UC Proxy Capture 4 | Testing only 5 | 6 | --------------------------------------------------------------------------------