diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1a3eaff..b6e1492 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,6 +3,9 @@
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 8641d1c..2867911 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -3,6 +3,7 @@
+
diff --git a/NetGhost.iml b/NetGhost.iml
index 27b370c..76e5f6c 100644
--- a/NetGhost.iml
+++ b/NetGhost.iml
@@ -4,7 +4,6 @@
-
diff --git a/README.md b/README.md
index ed4b100..3ec6247 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# Network Ghost
-Android MAC/Hostname Spoofing in Lollipop 5.1 (And probably older Androids too) (tested on Galaxy S4 w/ cyanogenmod 12.1)
+Android MAC/Hostname Spoofing in Lollipop 5.1 (And probably older Androids too) (tested on Galaxy S4 and HTC One M7/M9 w/ cyanogenmod 12.1)
Change your mac address! Change your hostname! Fun for all the family! *
-\* May not actually be fun for ALL the family. Your dog probably doesn't care about this.
+\* May not actually be true.
![Screenshot](screenshots/screenshot.png)
@@ -24,6 +24,8 @@ Finally, there seems to be a distinct lack of open source apps that let me chang
## Where does it definitely work?
* Samsung Galaxy S4 running Cyanogenmod 12.1
+* HTC One M7
+* HTC One M9
NOTE: Some MAC addresses cannot be set. For example, "11:22:33:44:55:66" will not work on my S4 but "00:11:22:33:44:55" will.
@@ -31,7 +33,9 @@ NOTE: Some MAC addresses cannot be set. For example, "11:22:33:44:55:66" will no
Install the apk file!
## How do I use it?
-Open up the app, hit the toggle button to change "User-set" to "randomise" and hit "update". Verify the mac has really been changed to what the app says by opening up a terminal and running:
+Open up the app, flip the spoof switch. You will be asked to okay an update to /system files to allow this to work.
+
+Hit the toggle button to change "User-set" to "randomise" and hit "update". Verify the mac has really been changed to what the app says by opening up a terminal and running:
```
adb shell ip addr
```
@@ -76,7 +80,10 @@ It was necessary to turn it off the Android(TM) way, i.e.
```
svc wifi disable
```
-Which kills wpa_supplicant, allowing us to swap out the mac address and turn wifi back on (which restarts wpa_supplicant, forcing it to re-read the mac address into memory). I have kept the commands running in a root shell to a minimum, since the wifi start/stop can be achieved in java.
+Which kills wpa_supplicant, allowing us to swap out the mac address and turn wifi back on (which restarts wpa_supplicant, forcing it to re-read the mac address into memory).
+
+But some devices bring down the network interface when the wifi is turned off, not letting us change the mac address. And when it's brought back up, wpa_supplicant is started up and the mac address is locked in again! What a travesty!
+
+But it's okay, I've come up with a workaround. This app will now install the workaround into /system and this new method should be more portable across devices.
-## Extension: HTC one
-For my HTC one, the above method does not work because on wifi restart, the device is brought down and up before wpa_supplicant is called. /dev is mounted as tmpfs so to save flash read-write cycles, I made a script that replaces wpa_supplicant. Move /system/bin/wpa_supplicant to /system/bin/wpa_supplicant_real and adb push scripts/wpa_supplicant /system/bin/wpa_supplicant - the git version of the app will now push the mac address to /dev/mac and it will be set just before calling wpa_supplicant for realz.
+I have kept the commands running in a root shell to a minimum, since the wifi start/stop can be achieved in java.
diff --git a/app/app.iml b/app/app.iml
index c2924b6..4b14097 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -1,5 +1,5 @@
-
+
@@ -13,11 +13,8 @@
-
-
- generateDebugAndroidTestSources
- generateDebugSources
-
+
+
diff --git a/app/src/main/java/com/moosd/netghost/MainActivity.java b/app/src/main/java/com/moosd/netghost/MainActivity.java
index 43ebd7c..fe630fe 100644
--- a/app/src/main/java/com/moosd/netghost/MainActivity.java
+++ b/app/src/main/java/com/moosd/netghost/MainActivity.java
@@ -1,6 +1,8 @@
package com.moosd.netghost;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.Editable;
@@ -19,14 +21,16 @@ public class MainActivity extends Activity {
EditText macEntry = null, hostEntry = null;
ToggleButton macToggle = null, hostToggle = null;
- Button updateButton = null, revertButton = null;
+ Button updateButton = null, revertButton = null, uninstallButton = null;
SharedPreferences settings = null;
Switch spoofSwitch = null;
+ public static MainActivity me = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ me = this;
settings = getSharedPreferences("settings", 0);
@@ -38,6 +42,7 @@ protected void onCreate(Bundle savedInstanceState) {
updateButton = ((Button) findViewById(R.id.button3));
revertButton = ((Button) findViewById(R.id.button));
+ uninstallButton = ((Button) findViewById(R.id.button4));
spoofSwitch = ((Switch) findViewById(R.id.switch1));
@@ -46,7 +51,12 @@ protected void onCreate(Bundle savedInstanceState) {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// update settings
- settings.edit().putBoolean("spoofenabled", isChecked).commit();
+ if(!Util.isInstalled() && isChecked) {
+ Util.askToInstall(MainActivity.this, true);
+ }
+ if(Util.isInstalled()) {
+ settings.edit().putBoolean("spoofenabled", isChecked).commit();
+ }
// update ux
updateUX();
}
@@ -182,6 +192,26 @@ public void onClick(View v) {
}
});
+ uninstallButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new AlertDialog.Builder(MainActivity.this)
+ .setTitle("Unnstall")
+ .setMessage("Are you sure you want to uninstall the changes to /system? You will not be able to modify your mac address.")
+ .setNegativeButton("No", null)
+ .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ settings.edit().putBoolean("spoofenabled", false).commit();
+ Util.uninstall(MainActivity.this);
+ updateUX();
+ }
+ })
+ .create()
+ .show();
+ }
+ });
+
}
@Override
@@ -190,7 +220,7 @@ protected void onResume() {
updateUX();
}
- private void updateUX() {
+ public void updateUX() {
boolean macrandomise = settings.getBoolean("macrandomise", false), hostrandomise = settings.getBoolean("hostrandomise", false), spoofenabled = settings.getBoolean("spoofenabled", true);
macEntry.setText(settings.getString("macset", Util.getMAC()));
@@ -200,6 +230,8 @@ private void updateUX() {
macToggle.setEnabled(spoofenabled);
hostToggle.setEnabled(spoofenabled);
+ uninstallButton.setEnabled(Util.isInstalled());
+
if(spoofenabled) {
macToggle.setChecked(macrandomise);
macEntry.setEnabled(!macrandomise);
diff --git a/app/src/main/java/com/moosd/netghost/Util.java b/app/src/main/java/com/moosd/netghost/Util.java
index e3c8b98..e9429ec 100644
--- a/app/src/main/java/com/moosd/netghost/Util.java
+++ b/app/src/main/java/com/moosd/netghost/Util.java
@@ -1,14 +1,20 @@
package com.moosd.netghost;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.net.wifi.WifiManager;
+import android.provider.ContactsContract;
import com.stericson.RootTools.RootTools;
import com.stericson.RootTools.exceptions.RootDeniedException;
import com.stericson.RootTools.execution.Command;
import com.stericson.RootTools.execution.CommandCapture;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Random;
import java.util.concurrent.TimeoutException;
@@ -17,6 +23,196 @@
*/
public class Util {
+ public static void askToInstall(final Context ctx, final boolean update) {
+ new AlertDialog.Builder(ctx)
+ .setTitle("Install")
+ .setMessage("To set this up I need to modify your system partition. This might brick your device (but shouldnt). You cool with that?")
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ performInstall(ctx);
+ if (update) {
+ if (Util.isInstalled()) {
+ MainActivity.me.settings.edit().putBoolean("spoofenabled", true).commit();
+ }
+ MainActivity.me.updateUX();
+ }
+ }
+ })
+ .create()
+ .show();
+ }
+
+ public static void askToInstall(final Context ctx) {
+ askToInstall(ctx, false);
+ }
+
+ public static void uninstall(Context ctx) {
+ // show loading menu
+ ProgressDialog dialog = ProgressDialog.show(ctx, "Uninstalling",
+ "Remounting system...", true);
+ dialog.show();
+ // remount system
+ final String[] result = {""};
+ Command command = new Command(0, "mount -o rw,remount /system") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+
+ // check if success
+ command = new Command(0, "mount|grep system") {
+ @Override
+ public void output(int id, String line) {
+ if(line.contains("rw")) result[0] = "yes";
+ }
+ };
+ runCmd(command);
+ if(!result[0].equals("yes")) {
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error remounting system. Sorry! Nothing was touched.").setPositiveButton("OK", null).create().show();
+ return;
+ }
+ result[0] = "";
+
+ dialog.setMessage("Moving wpa_supplicant back");
+ // move wpa_supplicant
+ command = new Command(0, "mv /system/bin/wpa_supplicant_real /system/bin/wpa_supplicant") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+
+ // check if success
+ command = new Command(0, "ls /system/bin/wpa_*") {
+ @Override
+ public void output(int id, String line) {
+ if(line.contains("_real")) result[0] = "yes";
+ }
+ };
+ runCmd(command);
+ if(result[0].equals("yes")) {
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error moving wpa_supplicant back. Sorry! Failed.").setPositiveButton("OK", null).create().show();
+ return;
+ }
+ result[0] = "";
+
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Success").setMessage("Uninstalled code successfully").setPositiveButton("OK", null).create().show();
+ }
+
+ public static void performInstall(Context ctx) {
+ // show loading menu
+ ProgressDialog dialog = ProgressDialog.show(ctx, "Installing",
+ "Remounting system...", true);
+ dialog.show();
+ // remount system
+ final String[] result = {""};
+ Command command = new Command(0, "mount -o rw,remount /system") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+
+ // check if success
+ command = new Command(0, "mount|grep system") {
+ @Override
+ public void output(int id, String line) {
+ if(line.contains("rw")) result[0] = "yes";
+ }
+ };
+ runCmd(command);
+ if(!result[0].equals("yes")) {
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error remounting system. Sorry! Nothing was touched.").setPositiveButton("OK", null).create().show();
+ return;
+ }
+ result[0] = "";
+
+ dialog.setMessage("Moving wpa_supplicant");
+ // move wpa_supplicant
+ command = new Command(0, "mv /system/bin/wpa_supplicant /system/bin/wpa_supplicant_real") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+
+ // check if success
+ command = new Command(0, "ls /system/bin/wpa_*") {
+ @Override
+ public void output(int id, String line) {
+ if(line.contains("_real")) result[0] = "yes";
+ }
+ };
+ runCmd(command);
+ if(!result[0].equals("yes")) {
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error moving wpa_supplicant. Sorry! Nothing was touched.").setPositiveButton("OK", null).create().show();
+ return;
+ }
+ result[0] = "";
+
+ // inject our script
+ dialog.setMessage("Injecting our mac changing code");
+
+ command = new Command(0, "echo '#!/system/xbin/bash|/system/xbin/busybox ifconfig wlan0 up hw ether $(cat /dev/mac)|/system/bin/wpa_supplicant_real $@' | sed 's/|/\\n/g' > /system/bin/wpa_supplicant", "chmod +x /system/bin/wpa_supplicant") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+ // check if success
+
+ if(isInstalled()) {
+ dialog.hide();
+ new AlertDialog.Builder(ctx).setTitle("Success").setMessage("Installed code successfully").setPositiveButton("OK", null).create().show();
+ } else {
+ //dialog.hide();
+ //new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error inserting our wpa_supplicant. Will try to revert now.").setPositiveButton("OK", null).create().show();
+ dialog.setMessage("Error inserting out wpa_supplicant. Trying to revert...");
+ command = new Command(0, "mv /system/bin/wpa_supplicant_real /system/bin/wpa_supplicant") {
+ @Override
+ public void output(int id, String line) {
+ }
+ };
+ runCmd(command);
+ command = new Command(0, "ls /system/bin/wpa_*") {
+ @Override
+ public void output(int id, String line) {
+ if(line.contains("_real")) result[0] = "yes";
+ }
+ };
+ runCmd(command);
+ if(result[0].equals("yes")) {
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Error reverting wpa_supplicant! System in inconsistent state.").setPositiveButton("OK", null).create().show();
+ } else {
+ new AlertDialog.Builder(ctx).setTitle("Error").setMessage("Reverted successfully.").setPositiveButton("OK", null).create().show();
+ }
+ dialog.hide();
+ }
+ }
+
+ public static boolean isInstalled() {
+ try {
+ byte[] buffer = new byte[4];
+ InputStream is = new FileInputStream("/system/bin/wpa_supplicant");
+ if (is.read(buffer) != buffer.length) {
+ }
+ is.close();
+ if (new String(buffer).equals("#!/s"))
+ return true;
+ else return false;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
public static void runCmd(Command command) {
boolean finished = false;
@@ -61,18 +257,30 @@ public static String randomHostname() {
}
public static void setMAC(String rmac, Context context) {
+ if (!isInstalled()) {
+ askToInstall(context);
+ return;
+ }
+ runCmd(new CommandCapture(0, "setenforce 0"));
+ try {
+ Thread.sleep(200);
+ } catch (Exception e) {
+ }
+
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(false);
try {
Thread.sleep(1000);
- } catch(Exception e){}
+ } catch (Exception e) {
+ }
System.out.println("setting MAC: " + rmac);
//runCmd(new CommandCapture(0, "busybox ifconfig wlan0 hw ether " + rmac));
runCmd(new CommandCapture(0, "echo \"" + rmac + "\" > /dev/mac"));
try {
Thread.sleep(200);
- } catch(Exception e){}
+ } catch (Exception e) {
+ }
wifi.setWifiEnabled(true);
}
@@ -88,7 +296,7 @@ public static String getMAC() {
public void output(int id, String line) {
if (line.contains("link/ether")) {
String[] split = line.trim().split(" ");
- System.out.println("MAC - "+split[1]);
+ System.out.println("MAC - " + split[1]);
result[0] = split[1];
}
}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index b7e5a3b..7fa4233 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,15 +1,16 @@
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
+ android:orientation="vertical">
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Spoofing"
+ android:id="@+id/switch1"/>
-
+ android:id="@+id/textView"/>
-
+
-
-
+ android:layout_weight="1"/>
-
-
-
+ android:textOn="Random"/>
+
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="Hostname Spoof:"
+ android:id="@+id/textView2"/>
-
+ android:layout_height="wrap_content" android:id="@+id/hostentry">
-
+ android:layout_weight="1"/>
-
+ android:textOn="Random"/>
-
+
-
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Update"
+ android:id="@+id/button3"/>
+
+
+
+
+
+
+
+
+ android:layout_gravity="bottom"
+ android:gravity="center">
+