Device.java 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package de.tudarmstadt.informatik.hostage.system;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.io.InputStreamReader;
  9. import java.io.OutputStream;
  10. import android.app.Activity;
  11. import android.util.Log;
  12. import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
  13. import de.tudarmstadt.informatik.hostage.ui.activity.MainActivity;
  14. public class Device {
  15. private static String porthackFilepath = "/data/local/bind";
  16. private static boolean initialized = false;
  17. private static boolean root = false; // device is rooted
  18. private static boolean porthack = false; // porthack installed
  19. private static boolean iptables = false; // iptables redirection confirmed working
  20. public static void checkCapabilities() {
  21. // assume worst case
  22. initialized = false;
  23. root = false;
  24. porthack = false;
  25. iptables = false;
  26. porthackFilepath = getPorthackFilepath();
  27. String porthackExists = "[ -e "+porthackFilepath+" ]"; // checks existence of porthack
  28. try {
  29. Process p = new ProcessBuilder("su", "-c", porthackExists).start();
  30. switch (p.waitFor()) {
  31. case 0: porthack = true;
  32. // fall through and don't break
  33. case 1: root = true; // 0 and 1 are valid return values of the porthack
  34. break;
  35. case 127: // command not found or executable
  36. root = false;
  37. porthack = false;
  38. break;
  39. }
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. } catch (InterruptedException e) {
  43. e.printStackTrace();
  44. }
  45. final String ipTablesList = "iptables -L -n -t nat"; // list all rules in NAT table
  46. try {
  47. Process p = new ProcessBuilder("su", "-c", ipTablesList).start();
  48. switch (p.waitFor()) {
  49. case 0: // everything is fine
  50. iptables = true; // iptables available and working
  51. break;
  52. case 3: // no such table
  53. case 127: // command not found
  54. default: // unexpected return code
  55. // while testing code 3 has been returned when table NAT is not available
  56. iptables = false;
  57. }
  58. } catch (IOException e) {
  59. e.printStackTrace();
  60. } catch (InterruptedException e) {
  61. e.printStackTrace();
  62. }
  63. initialized = true;
  64. }
  65. public static boolean isRooted() {
  66. assert(initialized);
  67. return root;
  68. }
  69. public static boolean isPorthackInstalled() {
  70. assert(initialized);
  71. return porthack;
  72. }
  73. public static boolean isPortRedirectionAvailable() { // using iptables
  74. assert(initialized);
  75. return iptables;
  76. }
  77. /**
  78. * copies an asset to the local filesystem for later usage
  79. * (used for port hack and shell scripts)
  80. * @param assetFilePath
  81. * @param destFilePath
  82. * @return true on success
  83. */
  84. private static boolean deployAsset(String assetFilePath, String destFilePath) {
  85. Activity activity = MainActivity.getInstance();
  86. File file = new File(activity.getFilesDir(), destFilePath);
  87. try {
  88. OutputStream os = new FileOutputStream(file);
  89. try {
  90. InputStream is = activity.getAssets().open(assetFilePath);
  91. byte[] buffer = new byte[4096];
  92. int bytesRead;
  93. while ((bytesRead = is.read(buffer)) != -1) {
  94. os.write(buffer, 0, bytesRead);
  95. }
  96. is.close();
  97. } catch (IOException e) {
  98. e.printStackTrace();
  99. }
  100. os.close();
  101. } catch (FileNotFoundException e) {
  102. e.printStackTrace();
  103. return false;
  104. } catch (IOException e) {
  105. e.printStackTrace();
  106. return false;
  107. }
  108. //Log.i("FILEPATH", file.getAbsolutePath());
  109. return true; // SUCCESS!
  110. }
  111. public static void executePortRedirectionScript() {
  112. assert(iptables); // we need iptables for our next trick
  113. if (deployAsset("payload/redirect-ports.sh", "redirect-ports.sh")) {
  114. String scriptFilePath = new File(MainActivity.getInstance().getFilesDir(), "redirect-ports.sh").getAbsolutePath();
  115. Process p = null;
  116. try {
  117. p = new ProcessBuilder("su", "-c", "sh "+scriptFilePath).start();
  118. p.waitFor(); // stall the main thread
  119. // TODO: check return value?
  120. } catch (IOException e) {
  121. e.printStackTrace();
  122. } catch (InterruptedException e) {
  123. e.printStackTrace();
  124. }
  125. }
  126. }
  127. /**
  128. * @return name of porthack binary for device architecture
  129. */
  130. private static String getPorthackName() {
  131. String porthack = "bind";
  132. // determine system architecture to return the correct binary
  133. String arch = System.getProperty("os.arch");
  134. // TODO: handle more architectures
  135. if (arch.equals("i686")) { // this is what genymotion reports
  136. porthack += ".x86";
  137. } else if (arch.startsWith("arm")) {
  138. /*
  139. possible values:
  140. armv4
  141. armv4t
  142. armv5t
  143. armv5te
  144. armv5tej
  145. armv6
  146. armv7
  147. */
  148. porthack += ".arm";
  149. } else if (arch.equals("mips")) {
  150. porthack += ".mips";
  151. }
  152. return porthack;
  153. }
  154. /**
  155. * @return filepath to deployed porthack binary
  156. */
  157. public static String getPorthackFilepath() {
  158. File file = new File(MainActivity.getInstance().getFilesDir(), getPorthackName());
  159. return file.getAbsolutePath();
  160. }
  161. public static boolean deployPorthack() {
  162. String porthack = getPorthackName();
  163. if (!deployAsset("payload/"+porthack, porthack)) {
  164. return false; // :(
  165. }
  166. // make port hack executable
  167. try {
  168. Process p = new ProcessBuilder("su", "-c", "chmod 700 "+getPorthackFilepath()).start();
  169. if (p.waitFor() != 0) {
  170. logError(p.getErrorStream());
  171. return false;
  172. }
  173. logOutput(p.getInputStream());
  174. } catch (IOException e) {
  175. return false;
  176. } catch (InterruptedException e) {
  177. return false;
  178. }
  179. return true; // SUCCESS!
  180. }
  181. public static void uninstallPorthack() {try {
  182. Process p = new ProcessBuilder("su", "-c", "rm "+getPorthackFilepath()).start();
  183. if (p.waitFor() != 0) {
  184. logError(p.getErrorStream());
  185. }
  186. logOutput(p.getInputStream());
  187. } catch (IOException e) {
  188. } catch (InterruptedException e) {
  189. }
  190. }
  191. // copied from PrivilegedPort.java
  192. private static void logOutput(InputStream stdout) throws IOException {
  193. BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
  194. String line;
  195. while ((line = reader.readLine()) != null) {
  196. Log.i("HelperUtils", line);
  197. }
  198. }
  199. private static void logError(InputStream stderr) throws IOException {
  200. BufferedReader reader = new BufferedReader(new InputStreamReader(stderr));
  201. Log.e("HelperUtils", reader.readLine());
  202. }
  203. }