package mobi.acpm.inspeckage.webserver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; import android.security.KeyPairGeneratorSpec; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.text.Html; import android.util.Log; import org.java_websocket.util.Base64; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.UUID; import javax.net.ssl.KeyManagerFactory; import javax.security.auth.x500.X500Principal; import fi.iki.elonen.NanoHTTPD; import mobi.acpm.inspeckage.Module; import mobi.acpm.inspeckage.hooks.CryptoHook; import mobi.acpm.inspeckage.hooks.FileSystemHook; import mobi.acpm.inspeckage.hooks.HashHook; import mobi.acpm.inspeckage.hooks.HttpHook; import mobi.acpm.inspeckage.hooks.IPCHook; import mobi.acpm.inspeckage.hooks.MiscHook; import mobi.acpm.inspeckage.hooks.SQLiteHook; import mobi.acpm.inspeckage.hooks.SerializationHook; import mobi.acpm.inspeckage.hooks.SharedPrefsHook; import mobi.acpm.inspeckage.hooks.UserHooks; import mobi.acpm.inspeckage.hooks.WebViewHook; import mobi.acpm.inspeckage.log.LogService; import mobi.acpm.inspeckage.receivers.InspeckageWebReceiver; import mobi.acpm.inspeckage.util.Config; import mobi.acpm.inspeckage.util.FileUtil; import mobi.acpm.inspeckage.util.PackageDetail; import mobi.acpm.inspeckage.util.Util; import static mobi.acpm.inspeckage.util.FileType.APP_STRUCT; import static mobi.acpm.inspeckage.util.FileType.CRYPTO; import static mobi.acpm.inspeckage.util.FileType.FILESYSTEM; import static mobi.acpm.inspeckage.util.FileType.HASH; import static mobi.acpm.inspeckage.util.FileType.HTTP; import static mobi.acpm.inspeckage.util.FileType.IPC; import static mobi.acpm.inspeckage.util.FileType.MISC; import static mobi.acpm.inspeckage.util.FileType.PREFS; import static mobi.acpm.inspeckage.util.FileType.SERIALIZATION; import static mobi.acpm.inspeckage.util.FileType.SQLITE; import static mobi.acpm.inspeckage.util.FileType.USERHOOKS; import static mobi.acpm.inspeckage.util.FileType.WEBVIEW; /** * Created by acpm on 16/11/15. */ public class WebServer extends fi.iki.elonen.NanoHTTPD { private Context mContext; private SharedPreferences mPrefs; private KeyStore keyStore; public WebServer(String host, int port, Context context) throws IOException { super(host,port); mContext = context; mPrefs = mContext.getSharedPreferences(Module.PREFS, mContext.MODE_WORLD_READABLE); SharedPreferences.Editor editor = mPrefs.edit(); editor.putBoolean("fake_board_key",true); editor.putBoolean("fake_bootloader_key",false); editor.putBoolean("fake_brand_key",false); editor.putBoolean("fake_cpu_abi_key",false); editor.putBoolean("fake_cpu_abi2_key",false); editor.putBoolean("fake_device_key",false); editor.putBoolean("fake_display_key",false); editor.putBoolean("fake_fingerprint_key",false); editor.putBoolean("fake_hardware_key",false); editor.putBoolean("fake_host_key",false); editor.putBoolean("fake_id_key",false); editor.putBoolean("fake_manufacturer_key",false); editor.putBoolean("fake_model_key",false); editor.putBoolean("fake_product_key",false); editor.putBoolean("fake_radio_key",false); editor.putBoolean("fake_tags_key",false); editor.putBoolean("fake_time_key",false); editor.putBoolean("fake_type_key",false); editor.putBoolean("fake_user_key",false); editor.putBoolean("fake_codename_key",false); editor.putBoolean("fake_incremental_key",false); editor.putBoolean("fake_release_key",false); editor.putBoolean("fake_sdk_key",false); editor.putBoolean("fake_sdk_int_key",false); editor.apply(); try { keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); Enumeration<String> aliases = keyStore.aliases(); List<String> keyAliases = new ArrayList<>(); while (aliases.hasMoreElements()) { keyAliases.add(aliases.nextElement()); } //use uuid as an alias, that way each installation has your own alias if(mPrefs.getString(Config.KEYPAIR_ALIAS,"").equals("")) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.KEYPAIR_ALIAS, UUID.randomUUID().toString()); edit.apply(); } String alias = mPrefs.getString(Config.KEYPAIR_ALIAS,""); boolean genNewKey = true; for (String key : keyAliases) { if(key.equals(alias)){ genNewKey = false; } } if(genNewKey) { KeyPair keyPair = generateKeys(alias); keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); } } catch(Exception e) { Log.e("Error",e.getMessage()); } if(mPrefs.getBoolean(Config.SP_SWITCH_AUTH, false)) { KeyManagerFactory keyManagerFactory = null; try { keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());// keyManagerFactory.init(keyStore, "".toCharArray()); } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) { e.printStackTrace(); } makeSecure(NanoHTTPD.makeSSLSocketFactory(keyStore, keyManagerFactory), null); } mContext.registerReceiver(new InspeckageWebReceiver(mContext), new IntentFilter("mobi.acpm.inspeckage.INSPECKAGE_WEB")); start(10000); } public KeyPair generateKeys(String alias) { KeyPair keyPair = null; try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA","AndroidKeyStore"); Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); end.add(Calendar.YEAR, 1); if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.M) { KeyGenParameterSpec spec= new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN|KeyProperties.PURPOSE_VERIFY) .setCertificateSubject(new X500Principal("CN=Inspeckage, OU=ACPM, O=ACPM, C=BR")) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) .setCertificateNotBefore(start.getTime()) .setCertificateNotAfter(end.getTime()) .setKeyValidityStart(start.getTime()) .setKeyValidityEnd(end.getTime()) .setKeySize(2048) .setCertificateSerialNumber(BigInteger.valueOf(1)) .build(); keyGen.initialize(spec); }else { KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(mContext) .setAlias(alias) .setSubject(new X500Principal("CN=Inspeckage, OU=ACPM, O=ACPM, C=BR")) .setSerialNumber(BigInteger.valueOf(12345)) .setStartDate(start.getTime()) .setEndDate(end.getTime()) .build(); keyGen.initialize(spec); } keyPair = keyGen.generateKeyPair(); } catch(GeneralSecurityException e) { Log.d("Inspeckage_Exception: ",e.getMessage()); } return keyPair; } private Response ok(String type, String html) { return newFixedLengthResponse(Response.Status.OK, type, html); } private Response ok(String html) { return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_HTML, html); } @Override public Response serve(IHTTPSession session) { String uri = session.getUri(); if(mPrefs.getBoolean(Config.SP_SWITCH_AUTH, false)) { Map<String, String> headers = session.getHeaders(); String authorization = headers.get("authorization"); String base64 = ""; if (authorization != null) { base64 = authorization.substring(6); } boolean logged = false; if (base64.equals(Base64.encodeBytes(mPrefs.getString(Config.SP_USER_PASS, "").getBytes()))) { logged = true; } if (!logged) { Response res = newFixedLengthResponse(Response.Status.UNAUTHORIZED, NanoHTTPD.MIME_HTML, "Denied!"); res.addHeader("WWW-Authenticate", "Basic realm=\"Server\""); res.addHeader("Content-Length", "0"); return res; } } //add ip and port to proxy fields if (mPrefs.getString(Config.SP_PROXY_HOST, "").equals("")) { String ip = session.getHeaders().get("http-client-ip"); if (ip != null && !ip.trim().equals("")) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_PROXY_HOST, ip); edit.putString(Config.SP_PROXY_PORT, "4443"); edit.apply(); } } Map<String, String> parms = session.getParms(); String type = parms.get("type"); String html = new String(); if (uri.equals("/")) { if (type != null) { switch (type) { case "startWS": return startWS(parms); case "stopWS": return stopWS(); case "filetree": return fileTreeHtml(); case "checkapp": return checkApp(); case "downloadfile": return downloadFile(parms); case "screenshot": return takeScreenshot(); case "setarp": return setArp(parms); case "downapk": return downloadApk(); case "downall": return downloadAll(); case "finishapp": finishApp(); return ok("OK"); case "restartapp": finishApp(); startApp(); return ok("OK"); case "startapp": startApp(); return ok("OK"); case "start": return startComponent(parms); case "file": html = fileHtml(parms); break; case Config.SP_EXPORTED: html = spExported(parms); break; case "flagsec": html = flagSecure(parms); break; case "proxy": html = proxy(parms); break; case "switchproxy": html = switchProxy(parms); break; case "sslunpinning": html = sslUnpinning(parms); break; case "adduserhooks": return addUserHooks(parms); case "addparamreplaces": return addUserReplaces(parms); case "addreturnreplaces": return addUserReturnReplaces(parms); case "getuserhooks": return getUserHooks(); case "getparamreplaces": return getUserReplaces(); case "getreturnreplaces": return getUserReturnReplaces(); case "getbuild": return getBuild(); case "addbuild": return addBuild(parms); case "deleteLogs": return clearHooksLog(parms); case "enableTab": html = tabsCheckbox(parms); break; case "clipboard": return addToClipboard(parms); } } else { html = setDefaultOptions(); } } else if (uri.equals("/index.html")) { html = FileUtil.readHtmlFile(mContext, uri); } else if (uri.equals("/logcat.html")) { html = FileUtil.readHtmlFile(mContext, uri); html = html.replace("#ip_ws#", mPrefs.getString(Config.SP_SERVER_IP, "127.0.0.1")); html = html.replace("#port_ws#", String.valueOf(mPrefs.getInt(Config.SP_WSOCKET_PORT, 8887))); return ok(html); } else if (uri.contains("/content/")) { html = FileUtil.readHtmlFile(mContext, uri); } else if (uri.equals("/struct")) { String json = FileUtil.readFromFile(mPrefs, APP_STRUCT);//readHtmlFile(mContext, uri); return ok("text/json", json); } else { String fname = FileUtil.readHtmlFile(mContext, uri); if (uri.contains(".css")) { return ok("text/css", fname); } if (uri.contains(".js")) { return ok("text/javascript", fname); } if (uri.contains(".png")) { try { InputStream f = mContext.getAssets().open("HTMLFiles" + uri); return newChunkedResponse(Response.Status.OK, "image/png", f); //return new Response(Response.Status.OK, "image/png", f, f.available()); } catch (IOException e) { e.printStackTrace(); } } if (uri.contains(".ico")) { return ok("image/vnd.microsoft.icon", fname); } if (uri.contains(".eot")) { return ok("application/vnd.ms-fontobject", fname); } if (uri.contains(".svg")) { return ok("image/svg+xml", fname); } if (uri.contains(".ttf")) { return ok("application/x-font-ttf", fname); } if (uri.contains(".woff")) { return ok("application/font-woff", fname); } if (uri.contains(".woff2")) { return ok("font/woff2", fname); } return ok(fname); } if (mPrefs.getBoolean(Config.SP_EXPORTED, false)) { PackageDetail pd = new PackageDetail(mContext, mPrefs.getString(Config.SP_PACKAGE, "")); SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_EXP_ACTIVITIES, pd.getExportedActivities()); edit.putString(Config.SP_N_EXP_ACTIVITIES, pd.getNonExportedActivities()); edit.apply(); } if (!mPrefs.getString(Config.SP_DATA_DIR_TREE, "").equals("")) { html = html.replace("#filetree#", mPrefs.getString(Config.SP_DATA_DIR_TREE, "")); } String moduleEnable = "true"; if (!isModuleEnabled()) { moduleEnable = "<font style=\"color:red; background:yellow;\">false</font>"; } html = html.replace("#moduleEnable#", moduleEnable); html = replaceHtmlVariables(html); //Inspeckage version PackageInfo pInfo; try { pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); String version = pInfo.versionName; html = html.replace("#inspeckageVersion#", version); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return ok(html); } private String setDefaultOptions() { SharedPreferences.Editor edit = mPrefs.edit(); edit.putBoolean(Config.SP_APP_IS_RUNNING, false); edit.putString(Config.SP_DATA_DIR_TREE, ""); edit.apply(); isRunning(); fileTree(); return FileUtil.readHtmlFile(mContext, "/index.html"); } private String tabsCheckbox(Map<String, String> parms) { String tab = parms.get("tab"); if (tab != null) { String state = parms.get("value"); SharedPreferences.Editor edit = mPrefs.edit(); switch (tab){ case "shared": edit.putBoolean(Config.SP_TAB_ENABLE_SHAREDP, Boolean.valueOf(state)); break; case "serialization": edit.putBoolean(Config.SP_TAB_ENABLE_SERIALIZATION, Boolean.valueOf(state)); break; case "crypto": edit.putBoolean(Config.SP_TAB_ENABLE_CRYPTO, Boolean.valueOf(state)); break; case "hash": edit.putBoolean(Config.SP_TAB_ENABLE_HASH, Boolean.valueOf(state)); break; case "sqlite": edit.putBoolean(Config.SP_TAB_ENABLE_SQLITE, Boolean.valueOf(state)); break; case "http": edit.putBoolean(Config.SP_TAB_ENABLE_HTTP, Boolean.valueOf(state)); break; case "filesystem": edit.putBoolean(Config.SP_TAB_ENABLE_FS, Boolean.valueOf(state)); break; case "misc": edit.putBoolean(Config.SP_TAB_ENABLE_MISC, Boolean.valueOf(state)); break; case "webview": edit.putBoolean(Config.SP_TAB_ENABLE_WV, Boolean.valueOf(state)); break; case "ipc": edit.putBoolean(Config.SP_TAB_ENABLE_IPC, Boolean.valueOf(state)); break; case "phooks": edit.putBoolean(Config.SP_TAB_ENABLE_PHOOKS, Boolean.valueOf(state)); break; } edit.apply(); } return "#tab_scheckbox#"; } private String sslUnpinning(Map<String, String> parms) { String ssl_switch = parms.get("sslswitch"); if (ssl_switch != null) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putBoolean(Config.SP_UNPINNING, Boolean.valueOf(ssl_switch)); edit.apply(); if (Boolean.valueOf(ssl_switch)) Util.showNotification(mContext, "Disable SSL"); } return "#sslunpinning#"; } private String switchProxy(Map<String, String> parms) { String pswitch = parms.get("value"); if (pswitch != null) { String host = mPrefs.getString(Config.SP_PROXY_HOST, ""); String port = mPrefs.getString(Config.SP_PROXY_PORT, ""); SharedPreferences.Editor edit = mPrefs.edit(); if (Boolean.valueOf(pswitch) && host.length() > 1 && port.length() > 0) { edit.putBoolean(Config.SP_SWITCH_PROXY, true); Util.showNotification(mContext, "Proxy Enable"); } else { edit.putBoolean(Config.SP_SWITCH_PROXY, false); } edit.apply(); } return "#proxy#"; } private String proxy(Map<String, String> parms) { String host = parms.get("host"); String port = parms.get("port"); if (host != null && port != null && Util.isInt(port)) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_PROXY_PORT, port); edit.putString(Config.SP_PROXY_HOST, host); edit.apply(); Util.showNotification(mContext, "Save Proxy: " + host + ":" + port); } return "#proxy#"; } private String flagSecure(Map<String, String> parms) { String fs_switch = parms.get("fsswitch"); if (fs_switch != null) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putBoolean(Config.SP_FLAG_SECURE, Boolean.valueOf(fs_switch)); edit.apply(); if (Boolean.valueOf(fs_switch)) Util.showNotification(mContext, "Disable all FLAG_SECURE"); } return "#flags#"; } private String spExported(Map<String, String> parms) { String value = parms.get("value"); if (value != null) { SharedPreferences.Editor edit = mPrefs.edit(); edit.putBoolean(Config.SP_EXPORTED, Boolean.valueOf(value)); edit.apply(); if (Boolean.valueOf(value)) Util.showNotification(mContext, "Export all activities"); } return "#exported#"; } private String fileHtml(Map<String, String> parms) { String value = parms.get("value"); int count = 0; String c = parms.get("count"); if (c == null || c.equals("")) { c = "0"; } count = Integer.valueOf(c); if (value != null && !value.trim().equals("")) { return hooksContent(value, count); } return ""; } private Response startComponent(Map<String, String> parms) { String component = parms.get("component"); if (component.equals("activity")) { String activity = parms.get("activity"); String action = parms.get("action"); String category = parms.get("category"); String data_uri = parms.get("datauri"); String extra = parms.get("extra"); String flags = parms.get("flags"); String mimetype = parms.get("mimetype"); startActivity(activity, action, category, data_uri, extra, flags, mimetype); } else if (component.equals("service")) { } else if (component.equals("broadcast")) { } else if (component.equals("provider")) { String uri_provider = parms.get("uri"); return queryProvider(uri_provider); } return ok(""); } private Response setArp(Map<String, String> parms) { String ip = parms.get("ip"); String mac = parms.get("mac"); Util.setARPEntry(ip, mac); Util.showNotification(mContext, "arp -s " + ip + " " + mac + ""); return ok("OK"); } private Response addToClipboard(Map<String, String> parms) { String value = parms.get("value"); Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_WEB"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("value", value); intent.putExtra("action", "clipboard"); mContext.sendBroadcast(intent, null); return ok("OK"); } private Response downloadFile(Map<String, String> parms) { String path = parms.get("value"); return downloadFileRoot(path); } private Response checkApp() { String isRunning = "App is running: true"; if (!mPrefs.getBoolean(Config.SP_APP_IS_RUNNING, false)) { isRunning = "App is running: <font style=\"color:red; background:yellow;\">false</font>"; } return ok(isRunning); } private Response fileTreeHtml() { String tree = mPrefs.getString(Config.SP_DATA_DIR_TREE, ""); if (tree.equals("")) { tree = "<p class=\"text-danger\">The app is running?</p>"; } return ok(tree); } private Response startWS(Map<String, String> parms) { String selected = parms.get("selected"); Intent i = new Intent(mContext, LogService.class); i.putExtra("filter",selected); i.putExtra("port", mPrefs.getInt(Config.SP_WSOCKET_PORT, 8887)); mContext.startService(i); return ok("OK"); } private Response stopWS() { mContext.stopService(new Intent(mContext, LogService.class)); return ok("OK"); } private Response addUserHooks(Map<String, String> parms) { String json = parms.get("jhooks"); SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_USER_HOOKS, json); edit.apply(); return ok("OK"); } private Response addUserReplaces(Map<String, String> parms) { String json = parms.get("data"); SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_USER_REPLACES, json); edit.apply(); return ok("OK"); } private Response addUserReturnReplaces(Map<String, String> parms) { String json = parms.get("data"); SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_USER_RETURN_REPLACES, json); edit.apply(); return ok("OK"); } private Response getUserHooks() { String json = mPrefs.getString(Config.SP_USER_HOOKS,""); return ok("text/json", json); } private Response getUserReplaces() { String json = mPrefs.getString(Config.SP_USER_REPLACES,""); return ok("text/json", json); } private Response getUserReturnReplaces() { String json = mPrefs.getString(Config.SP_USER_RETURN_REPLACES,""); return ok("text/json", json); } private Response getBuild() { String json = mPrefs.getString(Config.SP_BUILD_HOOKS,""); json = json.replace("{\"buildItems\":[{","[{"); json = json.replace("\"}]}","\"}]"); return ok("text/json", json); } private Response addBuild(Map<String, String> parms) { String json = parms.get("build"); json = "{\"buildItems\":"+json+"}"; SharedPreferences.Editor edit = mPrefs.edit(); edit.putString(Config.SP_BUILD_HOOKS, json); edit.apply(); return ok("OK"); } private Response clearHooksLog(Map<String, String> parms) { String hook = parms.get("value"); String appPath = Environment.getExternalStorageDirectory().getAbsolutePath(); if (!mPrefs.getBoolean(Config.SP_HAS_W_PERMISSION, false)) { appPath = mPrefs.getString(Config.SP_DATA_DIR, ""); } String path = ""; switch (hook) { case "userhooks": path = Config.P_USERHOOKS; break; case "misc": path = Config.P_MISC; break; case "webview": path = Config.P_WEBVIEW; break; case "http": path = Config.P_HTTP; break; case "fs": path = Config.P_FILESYSTEM; break; case "ipc": path = Config.P_IPC; break; case "sqlite": path = Config.P_SQLITE; break; case "hash": path = Config.P_HASH; break; case "crypto": path = Config.P_CRYPTO; break; case "serialization": path = Config.P_SERIALIZATION; break; case "prefs": path = Config.P_PREFS; break; } File root = new File(appPath + Config.P_ROOT + path); FileUtil.deleteFile(root); return ok("ok"); } private String replaceHtmlVariables(String html) { html = html.replace("#proxy#", htmlProxy()); html = html.replace("#flags#", flagSecureCheckbox()); html = html.replace("#sslunpinning#", SSLUnpinningCheckbox()); html = html.replace("#exported#", exportedCheckbox()); html = html.replace("#tab_scheckbox#", tabsCheckbox()); html = html.replace("#exported_act#", htmlExportedActivities()); html = html.replace("#activities_list#", htmlActivityList()); html = html.replace("#exported_provider#", htmlExportedProviders()); html = html.replace("#non_exported_provider#", htmlNonExportedProviders()); html = html.replace("#exported_services#", htmlExportedServices()); html = html.replace("#exported_broadcast#", htmlExportedBroadcasts()); html = html.replace("#appName#", mPrefs.getString(Config.SP_APP_NAME, "AppName")); String icon = "<img src=\"data:image/png;base64, "+mPrefs.getString(Config.SP_APP_ICON_BASE64, "AppIcon")+"\" width=\"80\" height=\"80\" />"; html = html.replace("#appIcon#", icon); html = html.replace("#appVersion#", mPrefs.getString(Config.SP_APP_VERSION, "Version")); html = html.replace("#uid#", mPrefs.getString(Config.SP_UID, "uid")); html = html.replace("#gids#", mPrefs.getString(Config.SP_GIDS, "GIDs")); html = html.replace("#package#", mPrefs.getString(Config.SP_PACKAGE, "package")); html = html.replace("#data_dir#", mPrefs.getString(Config.SP_DATA_DIR, "Data Path")); html = html.replace("#isdebuggable#", mPrefs.getString(Config.SP_DEBUGGABLE, "?")); html = html.replace("#allowbackup#", mPrefs.getString(Config.SP_ALLOW_BACKUP, "?")); html = html.replace("#non_exported_act#", mPrefs.getString(Config.SP_N_EXP_ACTIVITIES, "Non Exported Activities").replace("\n", "</br>")); html = html.replace("#non_exported_services#", mPrefs.getString(Config.SP_N_EXP_SERVICES, "Services").replace("\n", "</br>")); html = html.replace("#non_exported_broadcast#", mPrefs.getString(Config.SP_N_EXP_BROADCAST, "Broadcast Receiver").replace("\n", "</br>")); html = html.replace("#req_permissions#", mPrefs.getString(Config.SP_REQ_PERMISSIONS, "Permissions").replace("\n", "</br>")); html = html.replace("#app_permissions#", mPrefs.getString(Config.SP_APP_PERMISSIONS, "Permissions").replace("\n", "</br>")); html = html.replace("#shared_libraries#", mPrefs.getString(Config.SP_SHARED_LIB, "Shared Libraries").replace("\n", "</br>")); return html; } //HTML public String htmlNonExportedProviders() { String act = mPrefs.getString(Config.SP_N_EXP_PROVIDER, "Non Exported Providers"); String[] providers = act.split("\n"); StringBuilder sb = new StringBuilder(); int i = 0; for (String provider : providers) { if (!provider.trim().equals("")) { if (provider.contains("GRANT:")) { String[] actInfo = provider.split("GRANT:"); String info = "<a data-toggle=\"collapse\" href=\"#collapsenprovider" + i + "\" aria-expanded=\"false\" aria-controls=\"collapsenprovider" + i + "\">" + actInfo[0] + "</a>" + "<div class=\"collapse\" id=\"collapsenprovider" + i + "\"><div class=\"well\">Grant URI Permission: " + actInfo[1].replace("|", "</br>") + "</div></div>"; i++; sb.append(info + "</br>"); } else { sb.append(provider + "</br>"); } } } return sb.toString(); } public String htmlExportedProviders() { String act = mPrefs.getString(Config.SP_EXP_PROVIDER, "Exported Providers"); String[] providers = act.split("\n"); StringBuilder sb = new StringBuilder(); int i = 0; for (String provider : providers) { if (!provider.trim().equals("")) { if (provider.contains("GRANT:")) { String[] actInfo = provider.split("GRANT:"); String info = "<a data-toggle=\"collapse\" href=\"#collapseprovider" + i + "\" aria-expanded=\"false\" aria-controls=\"collapseprovider" + i + "\">" + actInfo[0] + "</a>" + "<div class=\"collapse\" id=\"collapseprovider" + i + "\"><div class=\"well\">Grant URI Permission: " + actInfo[1].replace("|", "</br>") + "</div></div>"; i++; sb.append(info + "</br>"); } else { sb.append(provider + "</br>"); } } } return sb.toString(); } public String htmlExportedBroadcasts() { String act = mPrefs.getString(Config.SP_EXP_BROADCAST, "Exported Broadcasts"); String[] broadcasts = act.split("\n"); StringBuilder sb = new StringBuilder(); int i = 0; for (String broadcast : broadcasts) { if (!broadcast.trim().equals("")) { if (broadcast.contains("PERM:")) { String[] actInfo = broadcast.split("PERM:"); String info = "<a data-toggle=\"collapse\" href=\"#collapsebroadcast" + i + "\" aria-expanded=\"false\" aria-controls=\"collapsebroadcast" + i + "\">" + actInfo[0] + "</a>" + "<div class=\"collapse\" id=\"collapsebroadcast" + i + "\"><div class=\"well\">PERMISSION: " + actInfo[1] + "</div></div></br>"; i++; sb.append(info); } else { sb.append(broadcast + "</br>"); } } } return sb.toString(); } public String htmlExportedServices() { String act = mPrefs.getString(Config.SP_EXP_SERVICES, "Exported Services"); String[] services = act.split("\n"); StringBuilder sb = new StringBuilder(); int i = 0; for (String service : services) { if (!service.trim().equals("")) { if (service.contains("PERM:")) { String[] actInfo = service.split("PERM:"); String info = "<a data-toggle=\"collapse\" href=\"#collapseservice" + i + "\" aria-expanded=\"false\" aria-controls=\"collapseservice" + i + "\">" + actInfo[0] + "</a>" + "<div class=\"collapse\" id=\"collapseservice" + i + "\"><div class=\"well\">PERMISSION: " + actInfo[1] + "</div></div></br>"; i++; sb.append(info); } else { sb.append(service + "</br>"); } } } return sb.toString(); } public String htmlExportedActivities() { String act = mPrefs.getString(Config.SP_EXP_ACTIVITIES, "Exported Activities"); String[] activities = act.split("\n"); StringBuilder sb = new StringBuilder(); int i = 0; for (String activity : activities) { if (!activity.trim().equals("")) { if (activity.contains("PERM:")) { String[] actInfo = activity.split("PERM:"); String info = "<a data-toggle=\"collapse\" href=\"#collapseActivity" + i + "\" aria-expanded=\"false\" aria-controls=\"collapseActivity" + i + "\">" + actInfo[0] + "</a>" + "<div class=\"collapse\" id=\"collapseActivity" + i + "\"><div class=\"well\">PERMISSION: " + actInfo[1] + "</div></div>"; i++; sb.append(info + "</br>"); } else { sb.append(activity + "</br>"); } } } return sb.toString(); } public String htmlActivityList() { String act = mPrefs.getString(Config.SP_EXP_ACTIVITIES, "Exported Activities"); String[] activities = act.split("\n"); StringBuilder sb = new StringBuilder(); for (String activity : activities) { if (!activity.trim().equals("")) { if (activity.contains("PERM:")) { String[] actInfo = activity.split("PERM:"); sb.append("<li><a href=\"#\" onclick=\"selectAct('" + actInfo[0].trim() + "');\">" + actInfo[0].trim() + "</a></li>"); } else { sb.append("<li><a href=\"#\" onclick=\"selectAct('" + activity + "');\">" + activity + "</a></li>"); } } } String nact = mPrefs.getString(Config.SP_N_EXP_ACTIVITIES, "N Exported Activities"); String[] nactivities = nact.split("\n"); if(nactivities.length > 0){ sb.append("<li role='separator' class='divider'></li>"); } String disabled = ""; if(!mPrefs.getBoolean(Config.SP_APP_IS_RUNNING,false)){ disabled = "class='disabled'"; } for (String activity : nactivities) { if (!activity.trim().equals("")) { if (activity.contains("PERM:")) { String[] actInfo = activity.split("PERM:"); sb.append("<li "+disabled+"><a href=\"#\" onclick=\"selectAct('" + actInfo[0].trim() + "');\">N " + actInfo[0].trim() + "</a></li>"); } else { sb.append("<li "+disabled+"><a href=\"#\" onclick=\"selectAct('" + activity + "');\">N " + activity + "</a></li>"); } } } return sb.toString(); } public String htmlProxy() { //Proxy String host = mPrefs.getString(Config.SP_PROXY_HOST, ""); String port = mPrefs.getString(Config.SP_PROXY_PORT, ""); Boolean sw = mPrefs.getBoolean(Config.SP_SWITCH_PROXY, false); String flag_s = "<input type='checkbox' name='switch_proxy' data-size='mini' unchecked>"; if (sw) { flag_s = "<input type='checkbox' name='switch_proxy' data-size='mini' checked>"; } return "<input type='text' class='form-control input-sm' id='host' value='" + host + "' placeholder='192.168.1.337'>" + "<input type='text' class='form-control input-sm' id='port' value='" + port + "' placeholder='8081'>" + flag_s; } public String htmlPrefsAccordion() { Map<String, String> prefsFiles = FileUtil.readMultiFile(mPrefs, Config.PREFS_BKP); String prefs_files = ""; int i = 0; for (Map.Entry<String, String> e : prefsFiles.entrySet()) { String k = e.getKey(); String v = e.getValue(); i++; prefs_files += "<div class='panel panel-default'><div class='panel-heading' role='tab' id='heading" + i + "'>" + "<h4 class='panel-title'><a role='button' data-toggle='collapse' data-parent='#accordion' href='#collapse" + i + "' " + "aria-expanded='true' aria-controls='collapse" + i + "'> " + k + " </a> </h4> </div> <div id='collapse" + i + "' " + "class='panel-collapse collapse in' role='tabpanel' aria-labelledby='heading" + i + "'> " + "<div class='panel-body'><textarea rows='"+countLines(v)+"' style=\"border:none;width:100%\" readonly>" +v + "</textarea></div> </div> </div>"; } return prefs_files; } private static int countLines(String str){ String[] lines = str.split("\r\n|\r|\n"); return lines.length+1; } //CONFIG public String flagSecureCheckbox() { String flag_s = "<input type='checkbox' name='flag_sec' data-size='mini' unchecked>"; boolean fs = mPrefs.getBoolean(Config.SP_FLAG_SECURE, false); if (fs) { flag_s = "<input type='checkbox' name='flag_sec' data-size='mini' checked>"; } return flag_s; } public String SSLUnpinningCheckbox() { String flag_s = "<input type='checkbox' name='ssl_uncheck' data-size='mini' unchecked>"; boolean fs = mPrefs.getBoolean(Config.SP_UNPINNING, false); if (fs) { flag_s = "<input type='checkbox' name='ssl_uncheck' data-size='mini' checked>"; } return flag_s; } public String exportedCheckbox() { String flag_s = "<input type='checkbox' name='exported' data-size='mini' unchecked>"; boolean fs = mPrefs.getBoolean(Config.SP_EXPORTED, false); if (fs) { flag_s = "<input type='checkbox' name='exported' data-size='mini' checked>"; } return flag_s; } public String tabsCheckbox() { String shared = "<input type='checkbox' name='shared' data-size='mini' checked> Shared Preferences</br>"; String serialization = "<input type='checkbox' name='serialization' data-size='mini' checked> Serialization</br>"; String crypto = "<input type='checkbox' name='crypto' data-size='mini' checked> Crypto</br>"; String hash = "<input type='checkbox' name='hash' data-size='mini' checked> Hash</br>"; String sqlite = "<input type='checkbox' name='sqlite' data-size='mini' checked> SQLite</br>"; String http = "<input type='checkbox' name='http' data-size='mini' checked> HTTP</br>"; String filesystem = "<input type='checkbox' name='filesystem' data-size='mini' checked> File System</br>"; String misc = "<input type='checkbox' name='misc' data-size='mini' checked> Misc.</br>"; String webview = "<input type='checkbox' name='webview' data-size='mini' checked> WebView</br>"; String ipc = "<input type='checkbox' name='ipc' data-size='mini' checked> IPC</br>"; String phooks = "<input type='checkbox' name='phooks' data-size='mini' checked> + Hooks</br>"; StringBuilder sb = new StringBuilder(); if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_SHAREDP, true)) { shared = "<input type='checkbox' name='shared' data-size='mini' unchecked> Shared Preferences</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_SERIALIZATION, true)) { serialization = "<input type='checkbox' name='serialization' data-size='mini' unchecked> Serialization</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_CRYPTO, true)) { crypto = "<input type='checkbox' name='crypto' data-size='mini' unchecked> Crypto</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_HASH, true)) { hash = "<input type='checkbox' name='hash' data-size='mini' unchecked> Hash</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_SQLITE, true)) { sqlite = "<input type='checkbox' name='sqlite' data-size='mini' unchecked> SQLite</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_HTTP, true)) { http = "<input type='checkbox' name='http' data-size='mini' unchecked> HTTP</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_FS, true)) { filesystem = "<input type='checkbox' name='filesystem' data-size='mini' unchecked> File System</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_MISC, true)) { misc = "<input type='checkbox' name='misc' data-size='mini' unchecked> Misc.</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_WV, true)) { webview = "<input type='checkbox' name='webview' data-size='mini' unchecked> WebView</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_IPC, true)) { ipc = "<input type='checkbox' name='ipc' data-size='mini' unchecked> IPC</br>"; } if (!mPrefs.getBoolean(Config.SP_TAB_ENABLE_PHOOKS, true)) { phooks = "<input type='checkbox' name='phooks' data-size='mini' unchecked> + Hooks</br>"; } return sb.append("<div class=\"col-md-6\" style=\"line-height:200%;\">").append(shared).append(serialization).append(crypto).append(hash).append(sqlite).append(http).append("</div><div class=\"col-md-6\" style=\"line-height:200%;\">") .append(filesystem).append(misc).append(webview).append(ipc).append(phooks).append("</div>").toString(); } //ACTIONS public Response takeScreenshot() { int time = (int) Calendar.getInstance().getTimeInMillis(); String fileName = String.valueOf(time) + ".png"; Util.takeScreenshot(fileName); String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath(); String absolutePath = sdcardPath + Config.P_ROOT + "/"+ fileName; try { FileInputStream f = new FileInputStream(absolutePath); File file = new File(absolutePath); Response res = newChunkedResponse(Response.Status.OK, "image/png", f);//new Response(Response.Status.OK, "image/png", f, (int) file.length()); res.addHeader("Content-Disposition", "attachment;filename=" + fileName); return res; } catch (FileNotFoundException e) { //response with some alert e.printStackTrace(); } return null; } public Response downloadFileRoot(String path) { String filename = path.substring(path.lastIndexOf("/") + 1); String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath(); if(new File(sdcardPath + Config.P_ROOT ).exists() && new File("/storage/emulated/legacy").exists()){ sdcardPath = "/storage/emulated/legacy"; } String absolutePath = sdcardPath + Config.P_ROOT + "/" + filename; Util.copyFileRoot(path, absolutePath); try { FileInputStream f = new FileInputStream(absolutePath); File file = new File(absolutePath); Response res = newChunkedResponse(Response.Status.OK, "application/octet-stream", f);//new Response(Response.Status.OK, "application/octet-stream", f, (int) file.length()); res.addHeader("Content-Disposition", "attachment;filename=" + filename); file.delete(); return res; } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public Response downloadAll() { String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath(); try { int time = (int) Calendar.getInstance().getTimeInMillis(); String zipName = mPrefs.getString(Config.SP_PACKAGE, "") + "-" + String.valueOf(time) + ".zip"; String fullZipPath = sdcardPath + "/" + Config.P_ROOT + "/" + zipName; String fullPath = mPrefs.getString(Config.SP_DATA_DIR, "") + Config.P_ROOT; if (mPrefs.getBoolean(Config.SP_HAS_W_PERMISSION, false)) { fullPath = sdcardPath + "/" + Config.P_ROOT+ "/"+ mPrefs.getString(Config.SP_PACKAGE,""); } FileUtil.zipFolder(fullPath, fullZipPath); FileInputStream f = new FileInputStream(fullZipPath); File file = new File(fullZipPath); Response res = newChunkedResponse(Response.Status.OK, "application/zip", f);//new Response(Response.Status.OK, "application/zip", f, (int) file.length()); res.addHeader("Content-Disposition", "attachment;filename=" + file.getName()); return res; } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public Response downloadApk() { String absolutePath = mPrefs.getString(Config.SP_APK_DIR, ""); try { FileInputStream f = new FileInputStream(absolutePath); File file = new File(absolutePath); Response res = newChunkedResponse(Response.Status.OK, "application/vnd.android.package-archive", f);//new Response(Response.Status.OK, "application/vnd.android.package-archive", f, (int) file.length()); String appName = mPrefs.getString(Config.SP_PACKAGE, "") + ".apk"; res.addHeader("Content-Disposition", "attachment;filename=" + appName); return res; } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public void startApp() { PackageDetail pd = new PackageDetail(mContext, mPrefs.getString(Config.SP_PACKAGE, "")); Intent i = pd.getLaunchIntent(); mContext.startActivity(i); } public void finishApp() { Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_FILTER"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("action", "finish"); mContext.sendBroadcast(intent, null); } public void fileTree() { Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_FILTER"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("action", "fileTree"); mContext.sendBroadcast(intent, null); } public void isRunning() { Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_FILTER"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("action", "checkApp"); mContext.sendBroadcast(intent, null); } //COMPONENTS public void startActivity(String activity, String action, String category, String data_uri, String extra, String flags, String mimetype) { Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_FILTER"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("action", "startAct"); intent.putExtra("activity", activity); intent.putExtra("intent_action", action); intent.putExtra("data_uri", data_uri); intent.putExtra("extra", extra); intent.putExtra("flags", flags); intent.putExtra("mimetype", mimetype); intent.putExtra("category", category); if(mPrefs.getBoolean(Config.SP_APP_IS_RUNNING,false)){ mContext.sendBroadcast(intent, null); }else { Intent i = new Intent(); i.setClassName(mPrefs.getString(Config.SP_PACKAGE, ""), activity); //FLAGS if(!flags.trim().equals("")) { Field[] fields = Intent.class.getFields(); for (Field f : fields) { try { Object value = f.get(i); if (flags.trim().contains(f.getName())) { i.addFlags((int) value); } } catch (IllegalAccessException e) { e.printStackTrace(); } } }else{ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } //DATA_URI if(!data_uri.trim().equals("")){ Uri u = Uri.parse(data_uri); i.setData(u); } if(!category.trim().equals("")){ i.addCategory(category); } if(!mimetype.trim().equals("")){ i.normalizeMimeType(mimetype); } if(!extra.trim().equals("")){ String[] extras = new String[]{extra}; if(extra.contains(";")){ extras = extra.split(";"); } for(String e : extras){ String[] values = e.split(","); if(values.length==3){ if(values[0].trim().toLowerCase().equals("string")){ i.putExtra(values[1],values[2]); } if(values[0].trim().toLowerCase().equals("boolean")){ i.putExtra(values[1],Boolean.valueOf(values[2])); } if(values[0].trim().toLowerCase().equals("int")){ i.putExtra(values[1], Integer.valueOf(values[2])); } if(values[0].trim().toLowerCase().equals("float")){ i.putExtra(values[1],Float.valueOf(values[2])); } if(values[0].trim().toLowerCase().equals("double")){ i.putExtra(values[1],Double.valueOf(values[2])); } } } } mContext.startActivity(i); } } public Response queryProvider(String uri) { Intent intent = new Intent("mobi.acpm.inspeckage.INSPECKAGE_FILTER"); intent.putExtra("package", mPrefs.getString(Config.SP_PACKAGE, "")); intent.putExtra("action", "query"); intent.putExtra("uri", uri); mContext.sendBroadcast(intent, null); return newFixedLengthResponse(Response.Status.OK, NanoHTTPD.MIME_HTML, "OK"); } //HOOKS TABS public String hooksContent(String type, int count) { String html = ""; int countTmp = 0; switch (type) { case "serialization": { html = FileUtil.readFromFile(mPrefs, SERIALIZATION).replace(SerializationHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } if (x[i].length() > 170) { String len170 = x[i].substring(0, 135); String rest = x[i].substring(135); x[i] = "<div class=\"collapse-group\"> <span class=\"label label-info\">" + (i + 1) + "</span> " + len170 + "<div class=\"collapse\"><div class=\"breakWord\">" + rest + "</div></div><a class=\"a\" href=\"#\"> »</a></div>"; continue; } x[i] = "<span class=\"label label-info\">" + (i + 1) + "</span> " + x[i] + "</br>"; } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } //need load from here for callapse work correctaly String script = "<script>$(document).ready(function() {" + "$('a').on('click', function(e) {" + " e.preventDefault();" + " var $this = $(this);" + " var $collapse = $this.closest('.collapse-group').find('.collapse');" + " $collapse.collapse('toggle');" + " });" + "});</script>"; sb.append(script); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "fs": { html = FileUtil.readFromFile(mPrefs, FILESYSTEM).replace(FileSystemHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { x[i] = "<span class=\"label label-info\">" + (i + 1) + "</span> " + x[i]; if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i] + "</br>"); } if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "misc": { html = FileUtil.readFromFile(mPrefs, MISC).replace(MiscHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if (x[i].length() > 170) { x[i] = "<div class=\"breakWord\"><span class=\"label label-info\"> " + (i + 1) + "</span> " + x[i] + "</div>"; } else { x[i] = "<span class=\"label label-info\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br>"; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "http": { html = FileUtil.readFromFile(mPrefs, HTTP).replace(HttpHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if (x[i].length() > 170) { x[i] = "<div class=\"breakWord\"><span class=\"label label-info\">" + (i + 1) + "</span> " + x[i] + "</div>"; } else { String color = "label-info"; if (x[i].contains("Possible pinning")) { color = "label-danger"; } x[i] = "<span class=\"label " + color + "\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br>"; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "wv": { html = FileUtil.readFromFile(mPrefs, WEBVIEW).replace(WebViewHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if (x[i].contains("addJavascriptInterface(Object, ")) { x[i] = "<a href=\"#\" role=\"button\" class=\"btn popovers\" data-toggle=\"popover\" " + "title=\"\" data-content=\"" + "Injects the supplied Java object into this WebView. " + "The object is injected into the JavaScript context of the main frame, " + "using the supplied name. This allows the Java object's methods to " + "be accessed from JavaScript. <a href='http://developer.android.com/intl/pt-br/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)' target='_blank' title='link'> read more.</a>\">" + x[i] + " </a>"; } else { x[i] = x[i]; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (String aX : x) { sb.append(aX + "</br>"); } String script = "<script>$(document).ready(function() {" + "$('[data-toggle=popover]').popover({html:true})" + "});</script>"; sb.append(script); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "ipc": { html = FileUtil.readFromFile(mPrefs, IPC).replace(IPCHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { x[i] = "<span class=\"label label-default\">" + (i + 1) + "</span> " + x[i]; if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i] + "</br>"); } if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "crypto": { html = FileUtil.readFromFile(mPrefs, CRYPTO).replace(CryptoHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } if (x[i].length() > 170) { String len170 = x[i].substring(0, 135); String rest = x[i].substring(135); x[i] = "<div class=\"collapse-group\"> <span class=\"label label-info\">" + (i + 1) + "</span> " + len170 + "<div class=\"collapse\"><p class=\"breakWord\">" + rest + "</p></div><a class=\"a\" href=\"#\"> »</a></div>"; continue; } x[i] = "<span class=\"label label-info\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br>"; } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } //need load from here for callapse work correctaly String script = "<script>$(document).ready(function() {" + "$('a').on('click', function(e) {" + " e.preventDefault();" + " var $this = $(this);" + " var $collapse = $this.closest('.collapse-group').find('.collapse');" + " $collapse.collapse('toggle');" + " });" + "});</script>"; sb.append(script); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "prefs": { html = FileUtil.readFromFile(mPrefs, PREFS).replace(SharedPrefsHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { String color = "danger"; if (x[i].contains("GET[")) { color = "info"; } else if (x[i].contains("CONTAINS[")) { color = "warning"; } else if (x[i].contains("PUT[")) { color = "danger"; } if (x[i].length() > 170) { x[i] = "<tr><td><div class=\"breakWord\"><span class=\"label label-" + color + "\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</div></td></tr>"; } else { x[i] = "<tr><td><span class=\"label label-" + color + "\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br></td></tr>"; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); String tableBefore = "<table class=\"table\"><tbody>"; String tableAfter = "</tbody></table>"; //sb.append(tableBefore); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } //sb.append(tableAfter); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "hash": { html = FileUtil.readFromFile(mPrefs, HASH).replace(HashHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } if (x[i].length() > 170) { String len170 = x[i].substring(0, 135); String rest = x[i].substring(135); x[i] = "<div class=\"collapse-group\"> <span class=\"label label-info\">" + (i + 1) + "</span> " + len170 + "<div class=\"collapse\"><p class=\"breakWord\">" + rest + "</p></div><a class=\"a\" href=\"#\"> »</a></div>"; continue; } x[i] = "<span class=\"label label-info\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br>"; } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } //need load from here for callapse work correctaly String script = "<script>$(document).ready(function() {" + "$('a').on('click', function(e) {" + " e.preventDefault();" + " var $this = $(this);" + " var $collapse = $this.closest('.collapse-group').find('.collapse');" + " $collapse.collapse('toggle');" + " });" + "});</script>"; sb.append(script); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } case "sqlite": { html = FileUtil.readFromFile(mPrefs, SQLITE).replace(SQLiteHook.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { String color; if (x[i].contains("INSERT INTO")) { color = "label-info"; } else if (x[i].contains("UPDATE")) { color = "label-warning"; } else if (x[i].contains("execSQL(")) { color = "label-danger"; } else if (x[i].contains("SELECT")) { color = "label-success"; x[i].replace("\n", "</br>"); } else { color = "label-default"; } if (x[i].length() > 170) { x[i] = "<div class=\"breakWord\"><span class=\"label " + color + "\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</div>"; } else { x[i] = "<span class=\"label " + color + "\">" + (i + 1) + "</span> " + Html.escapeHtml(x[i]) + "</br>"; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i]); } if (count == -1) { html = sb.toString().replace("</br></br>", "</br>"); } else { html = "" + countTmp; } } break; } case "userhooks": { html = FileUtil.readFromFile(mPrefs, USERHOOKS).replace(UserHooks.TAG, ""); if(!html.equals("")) { String[] x = html.split("</br>"); for (int i = 0; i < x.length; i++) { if (x[i].length() > 470) { String len300 = x[i].substring(0, 400); String rest = x[i].substring(400); x[i] = "<div class=\"collapse-group\"> <div class=\"breakWord\"><span class=\"label label-default\">" + (i + 1) + "</span> " + len300 + "</div>" + "<div class=\"collapse\"><p class=\"breakWord\">" + rest + "</p></div><a class=\"a\" href=\"#\"> »</a></div>"; } else { x[i] = "<span class=\"label label-default\">" + (i + 1) + "</span> " + x[i]; } if ((i + 1) > count) { countTmp = (i + 1); } else { countTmp = count; } } List<String> ls = Arrays.asList(x); Collections.reverse(ls); x = (String[]) ls.toArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < x.length; i++) { if (i < 500) sb.append(x[i] + "</br>"); } //need load from here for callapse work correctaly String script = "<script>$(document).ready(function() {" + "$('a').on('click', function(e) {" + " e.preventDefault();" + " var $this = $(this);" + " var $collapse = $this.closest('.collapse-group').find('.collapse');" + " $collapse.collapse('toggle');" + " });" + "});</script>"; sb.append(script); if (count == -1) { html = sb.toString(); } else { html = "" + countTmp; } } break; } } if (type.equals("pfiles")) { html = htmlPrefsAccordion(); } return html; } //TEST MODULE ENABLED public static boolean isModuleEnabled() { return false; } }