Heroes III HD v1.1.6版本的 MD5 值为:99ed52e2d6b85487933b8dc8c0440b36
以下内容为反编译后的 HostsBlocker.java 源代码,内容仅作参考
package com.begal.appclone.classes;
import andhook.lib.AndHook;
import andhook.lib.HookHelper;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.drive.DriveFile;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@SuppressLint({"StaticFieldLeak", "UseSparseArrays"})
public class HostsBlocker {
private static final String PREF_KEY_PREFIX = "com.begal.appclone.host_";
private static String sAllowLabel;
private static boolean sBlockByDefault;
private static String sBlockLabel;
private static String sContentText;
private static String sContentTitle;
private static Context sContext;
private static String sHostBlockedMessage;
private static String sHostsBlockerTitle;
private static String sIgnoreLabel;
private static NotificationManager sNotificationManager;
private static SharedPreferences sPreferences;
private static String sSocksProxyHost;
private static final String TAG = HostsBlocker.class.getSimpleName();
private static Set<String> sHostsFileHosts = new HashSet();
private static final Map<String, Boolean> sHosts = Collections.synchronizedMap(new HashMap());
private static final Map<Integer, String> sNotifications = Collections.synchronizedMap(new HashMap());
private static Handler sHandler = new Handler();
@SuppressLint({"PrivateApi"})
public static void install(Context context, boolean blockByDefault, String socksProxyHost) {
sContext = context;
sBlockByDefault = blockByDefault;
sSocksProxyHost = socksProxyHost;
sNotificationManager = (NotificationManager) context.getSystemService("notification");
sPreferences = PreferenceManager.getDefaultSharedPreferences(context);
synchronized (sHosts) {
try {
BufferedReader r = new BufferedReader(new InputStreamReader(context.getAssets().open(".blockedHostsFile")));
try {
Pattern p = Pattern.compile("(?:0.0.0.0|127.0.0.1)\\s+(\\S*)");
while (true) {
String line = r.readLine();
if (line != null) {
String line2 = line.trim();
if (!line2.startsWith("#")) {
Matcher m = p.matcher(line2);
if (m.find()) {
String host = m.group(1);
String str = TAG;
Log.i(str, "install; host: " + host);
sHostsFileHosts.add(host);
}
}
} else {
try {
break;
} catch (Exception e) {
}
}
}
} finally {
try {
r.close();
} catch (Exception e2) {
}
}
} catch (FileNotFoundException e3) {
} catch (Exception e4) {
Log.w(TAG, e4);
}
for (String key : sPreferences.getAll().keySet()) {
if (key != null && key.startsWith(PREF_KEY_PREFIX)) {
boolean b = sPreferences.getBoolean(key, false);
sHosts.put(key.substring(PREF_KEY_PREFIX.length()), Boolean.valueOf(b));
}
}
String str2 = TAG;
Log.i(str2, "install; sHosts: " + sHosts);
}
try {
AndHook.ensureNativeLibraryLoaded(null);
Class<?> clazz = Class.forName("java.net.PlainSocketImpl");
AndHook.ensureClassInitialized(clazz);
AndHook.ensureClassInitialized(HostsBlocker.class);
HookHelper.hook(clazz.getDeclaredMethod("socketConnect", InetAddress.class, Integer.TYPE, Integer.TYPE), HostsBlocker.class.getMethod("socketConnectHook", Object.class, InetAddress.class, Integer.TYPE, Integer.TYPE));
Log.i(TAG, "install; socketConnectHook installed");
} catch (Throwable t) {
Log.w(TAG, t);
}
sHostsBlockerTitle = Utils.getAppClonerResourceText(sContext, "hosts_blocker_title", "Hosts blocker").toString();
sContentTitle = Utils.getAppClonerResourceText(sContext, "hosts_blocker_app_is_accessing_title", "%s is accessing").toString();
sContentText = Utils.getAppClonerResourceText(sContext, "hosts_blocker_touch_to_block_title", "Touch to block %s").toString();
sAllowLabel = Utils.getAppClonerResourceText(sContext, "label_allow", "Allow").toString();
sBlockLabel = Utils.getAppClonerResourceText(sContext, "label_block", "Block").toString();
sIgnoreLabel = Utils.getAppClonerResourceText(sContext, "label_ignore", "Ignore").toString();
sHostBlockedMessage = Utils.getAppClonerResourceText(sContext, "hosts_blocker_host_blocked_message", "Host %s blocked.").toString();
}
public static void socketConnectHook(Object instance, InetAddress address, int port, int timeout) throws UnknownHostException {
String str = TAG;
Log.i(str, "socketConnectHook; address: " + address + ", port: " + port + ", timeout: " + timeout);
checkHost(address);
HookHelper.invokeVoidOrigin(instance, address, Integer.valueOf(port), Integer.valueOf(timeout));
}
private static void checkHost(InetAddress address) throws UnknownHostException {
if (address == null) {
return;
}
checkHost(address.getHostName());
}
private static void checkHost(final String host) throws UnknownHostException {
if (host != null && host.length() > 0) {
if ((sSocksProxyHost != null && sSocksProxyHost.equals(host)) || "127.0.0.1".equals(host) || "localhost".equals(host) || host.startsWith("192.168.")) {
return;
}
List<String> list = splitHost(host);
for (String key : list) {
if (sHosts.containsKey(key)) {
Boolean b = sHosts.get(key);
if (b == null || b.booleanValue()) {
String str = TAG;
Log.i(str, "checkHost; ignored/allowed; host: " + host);
return;
}
String str2 = TAG;
Log.i(str2, "checkHost; blocked; host: " + host);
throw new UnknownHostException("Blocked");
} else if (sHostsFileHosts.contains(key)) {
addBlockedHost(host);
sHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(HostsBlocker.sContext, HostsBlocker.sHostBlockedMessage.replace("%s", host), 0).show();
}
});
String str3 = TAG;
Log.i(str3, "checkHost; blocked; host: " + host);
throw new UnknownHostException("Blocked");
}
}
notifyHost(host);
if (sBlockByDefault) {
throw new UnknownHostException("Blocked by default");
}
}
}
public static List<String> splitHost(String host) {
List<String> list = new ArrayList<>();
list.add(host);
boolean alpha = false;
int len = host.length();
int n = 0;
while (true) {
if (n < len) {
char c = host.charAt(n);
if (c == '.' || Character.isDigit(c)) {
n++;
} else {
alpha = true;
break;
}
} else {
break;
}
}
if (alpha) {
while (true) {
int pos = host.indexOf(46);
if (pos == -1) {
break;
}
host = host.substring(pos + 1);
if (host.indexOf(46) == -1) {
break;
}
list.add("*." + host);
}
}
return list;
}
private static void notifyHost(String host) {
int notificationId = host.hashCode();
synchronized (sNotifications) {
if (sNotifications.containsKey(Integer.valueOf(notificationId))) {
return;
}
sNotifications.put(Integer.valueOf(notificationId), host);
Log.i(TAG, "notifyHost; host: " + host);
int requestCode = host.hashCode();
PendingIntent contentIntent = PendingIntent.getBroadcast(sContext, requestCode, new Intent(host, null, sContext, ContentReceiver.class), 134217728);
PendingIntent allowIntent = PendingIntent.getBroadcast(sContext, requestCode + 1, new Intent(host, null, sContext, AllowReceiver.class), 1073741824);
PendingIntent blockIntent = PendingIntent.getBroadcast(sContext, requestCode + 2, new Intent(host, null, sContext, BlockReceiver.class), 1073741824);
PendingIntent ignoreIntent = PendingIntent.getBroadcast(sContext, requestCode + 3, new Intent(host, null, sContext, IgnoreReceiver.class), 1073741824);
PendingIntent cancelIntent = PendingIntent.getBroadcast(sContext, requestCode + 4, new Intent(Integer.toString(notificationId), null, sContext, CancelReceiver.class), 1073741824);
String contentTitle = sContentTitle.replace("%s", Utils.getAppName(sContext));
Notification.Builder builder = new Notification.Builder(sContext).setSmallIcon(17301543).setContentTitle(contentTitle).setContentIntent(contentIntent).setDeleteIntent(cancelIntent).setAutoCancel(false);
if (Build.VERSION.SDK_INT >= 16) {
builder.setContentText(host).addAction(requestCode, sAllowLabel, allowIntent).addAction(requestCode, sBlockLabel, blockIntent).addAction(requestCode, sIgnoreLabel, ignoreIntent);
} else {
String contentText = sContentText.replace("%s", host);
builder.setContentText(contentText).setContentIntent(blockIntent);
}
if (Build.VERSION.SDK_INT >= 21) {
builder.setVisibility(-1);
}
Utils.setSmallNotificationIcon(builder);
Notification notification = builder.getNotification();
notification.sound = null;
notification.defaults &= -2;
sNotificationManager.notify(notificationId, notification);
}
}
public static void addAllowedHost(String host) {
String str = TAG;
Log.i(str, "addAllowedHost; host: " + host);
sHosts.put(host, true);
synchronized (sPreferences) {
SharedPreferences.Editor edit = sPreferences.edit();
edit.putBoolean(PREF_KEY_PREFIX + host, true).apply();
}
}
public static void addBlockedHost(String host) {
String str = TAG;
Log.i(str, "addBlockedHost; host: " + host);
sHosts.put(host, false);
synchronized (sPreferences) {
SharedPreferences.Editor edit = sPreferences.edit();
edit.putBoolean(PREF_KEY_PREFIX + host, false).apply();
}
}
public static void addIgnoredHost(String host) {
String str = TAG;
Log.i(str, "addIgnoredHost; host: " + host);
sHosts.put(host, null);
}
public static void whois(Context context, String host) {
Log.i(TAG, "whois; host: " + host);
if (host.startsWith("*.")) {
host = host.substring(2);
}
try {
String url = "http://whois.domaintools.com/" + host;
Intent i = new Intent("android.intent.action.VIEW");
i.setFlags(DriveFile.MODE_READ_ONLY);
i.setData(Uri.parse(url));
context.startActivity(i);
} catch (Exception e) {
Log.w(TAG, e);
Toast.makeText(context, "Failed to open browser.", 1).show();
}
}
public static abstract class HostReceiver extends BroadcastReceiver {
protected abstract void handleHost(Context context, String str);
@Override
public void onReceive(Context context, Intent intent) {
try {
String host = intent.getAction();
if (!TextUtils.isEmpty(host)) {
handleHost(context, host);
}
} catch (Exception e) {
Log.w(HostsBlocker.TAG, e);
}
}
}
public static class ContentReceiver extends HostReceiver {
@Override
protected void handleHost(Context context, String host) {
String str = HostsBlocker.TAG;
Log.i(str, "ContentReceiver; handleHost; host: " + host);
Intent i = new Intent(context, HostsBlockerActivity.class);
i.setFlags(DriveFile.MODE_READ_ONLY);
i.putExtra("host", host);
context.startActivity(i);
}
}
public static class AllowReceiver extends HostReceiver {
@Override
protected void handleHost(Context context, String host) {
String str = HostsBlocker.TAG;
Log.i(str, "AllowReceiver; handleHost; host: " + host);
HostsBlocker.addAllowedHost(host);
HostsBlocker.removeNotification(host);
}
}
public static class BlockReceiver extends HostReceiver {
@Override
protected void handleHost(Context context, String host) {
String str = HostsBlocker.TAG;
Log.i(str, "BlockReceiver; handleHost; host: " + host);
HostsBlocker.addBlockedHost(host);
HostsBlocker.removeNotification(host);
}
}
public static class IgnoreReceiver extends HostReceiver {
@Override
protected void handleHost(Context context, String host) {
String str = HostsBlocker.TAG;
Log.i(str, "IgnoreReceiver; handleHost; host: " + host);
HostsBlocker.addIgnoredHost(host);
HostsBlocker.removeNotification(host);
}
}
public static class CancelReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
String notificationId = intent.getAction();
String str = HostsBlocker.TAG;
Log.i(str, "CancelReceiver; onReceive; notificationId: " + notificationId);
HostsBlocker.sNotifications.remove(Integer.valueOf(Integer.parseInt(notificationId)));
} catch (Exception e) {
Log.w(HostsBlocker.TAG, e);
}
}
}
public static class HostsBlockerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String host = getIntent().getStringExtra("host");
String str = HostsBlocker.TAG;
Log.i(str, "onCreate; host: " + host);
List<String> list = HostsBlocker.splitHost(host);
final String[] items = (String[]) list.toArray(new String[0]);
final AtomicReference<String> ref = new AtomicReference<>(items[0]);
AlertDialog.Builder builder = Utils.getDialogBuilder(this).setTitle(HostsBlocker.sHostsBlockerTitle).setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String item = items[which];
ref.set(item);
}
});
if (Build.VERSION.SDK_INT > 21) {
builder.setNeutralButton("Whois", (DialogInterface.OnClickListener) null).setNegativeButton(HostsBlocker.sAllowLabel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
HostsBlocker.addAllowedHost((String) ref.get());
HostsBlocker.removeNotification((String) ref.get());
}
}).setPositiveButton(HostsBlocker.sBlockLabel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
HostsBlocker.addBlockedHost((String) ref.get());
HostsBlocker.removeNotification((String) ref.get());
}
});
} else {
builder.setNegativeButton("Whois", (DialogInterface.OnClickListener) null).setNeutralButton(HostsBlocker.sAllowLabel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
HostsBlocker.addAllowedHost((String) ref.get());
HostsBlocker.removeNotification((String) ref.get());
}
}).setPositiveButton(HostsBlocker.sBlockLabel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
HostsBlocker.addBlockedHost((String) ref.get());
HostsBlocker.removeNotification((String) ref.get());
}
});
}
AlertDialog dialog = builder.create();
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog2) {
HostsBlockerActivity.this.finish();
}
});
dialog.show();
if (Build.VERSION.SDK_INT > 21) {
dialog.getButton(-3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
HostsBlocker.whois(HostsBlockerActivity.this, (String) ref.get());
}
});
} else {
dialog.getButton(-2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
HostsBlocker.whois(HostsBlockerActivity.this, (String) ref.get());
}
});
}
Utils.keepDialogOpenOnOrientationChange(dialog);
}
}
public static void removeNotification(String host) {
String str = TAG;
Log.i(str, "removeNotification; host: " + host);
try {
sNotificationManager.cancel(host.hashCode());
if (host.startsWith("*.")) {
host = host.substring(2);
}
synchronized (sNotifications) {
for (Integer notificationId : sNotifications.keySet()) {
String otherHost = sNotifications.get(notificationId);
if (otherHost.endsWith(host)) {
sNotificationManager.cancel(notificationId.intValue());
}
}
}
} catch (Exception e) {
Log.w(TAG, e);
}
}
}