diff --git a/.idea/misc.xml b/.idea/misc.xml index e0d5b93..51fa3e5 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,7 +5,7 @@ diff --git a/app/app-release.apk b/app/app-release.apk index 72ec5d2..19a0c19 100644 Binary files a/app/app-release.apk and b/app/app-release.apk differ diff --git a/app/src/main/assets/pages/index.html b/app/src/main/assets/pages/index.html index 12dabd8..1ca5811 100644 --- a/app/src/main/assets/pages/index.html +++ b/app/src/main/assets/pages/index.html @@ -15,7 +15,7 @@

Tips

It can be used to locate/bypass network traffic encryption/sign.

Some Application may have several processes.To monitor specified process, you can use 'adb forward tcp:8000 tcp:[pid]' instead of 'adb forward tcp:8000 tcp:8000'

-

Request Infomations:

+

Request Infomations:

Available Operations: <#list opList as op> @@ -56,12 +56,15 @@

Request Infomations:

-

Known Classes:

+

Memory

+

Memory Editor allows you read/write/dump application's memory.

+

It can be used to extract .dex or .so file in the runtime.

+

View/Monitor Known Classes:

Filter:

- +
diff --git a/app/src/main/assets/pages/memory.html b/app/src/main/assets/pages/memory.html new file mode 100644 index 0000000..622740c --- /dev/null +++ b/app/src/main/assets/pages/memory.html @@ -0,0 +1,52 @@ + + + + MemoryReader + + +
+ Memory Maps + <#list maps as map> +

${map}

+ +
+

Memory Editor:

+

Address:

+

Count :

+ + + + +

+ + + + \ No newline at end of file diff --git a/app/src/main/java/monkeylord/XServer/XServer.java b/app/src/main/java/monkeylord/XServer/XServer.java index 696f05e..88aae6b 100644 --- a/app/src/main/java/monkeylord/XServer/XServer.java +++ b/app/src/main/java/monkeylord/XServer/XServer.java @@ -14,6 +14,7 @@ import monkeylord.XServer.api.ClassView; import monkeylord.XServer.api.Invoke; import monkeylord.XServer.api.Invoke_New; +import monkeylord.XServer.api.MemoryView; import monkeylord.XServer.api.MethodView; import monkeylord.XServer.api.Tracer; import monkeylord.XServer.api.wsMethodView; @@ -60,6 +61,7 @@ public XServer(int port, Hashtable route) { XServer.route.put("/tracer", new Tracer()); XServer.route.put("/invoke", new Invoke()); XServer.route.put("/invoke2", new Invoke_New()); + XServer.route.put("/memory", new MemoryView()); try { //启动监听 start(0, false); diff --git a/app/src/main/java/monkeylord/XServer/api/MemoryView.java b/app/src/main/java/monkeylord/XServer/api/MemoryView.java new file mode 100644 index 0000000..3ee6d61 --- /dev/null +++ b/app/src/main/java/monkeylord/XServer/api/MemoryView.java @@ -0,0 +1,91 @@ +package monkeylord.XServer.api; + +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import monkeylord.XServer.XServer; +import monkeylord.XServer.handler.MemoryHandler; +import monkeylord.XServer.handler.MethodHandler; + +public class MemoryView implements XServer.Operation { + @Override + public String handle(String url, Map parms, Map headers, Map files) { + try { + Method method=null; + if(parms.get("op")!=null) { + switch (parms.get("op")){ + case "dump": + byte[] binary=MemoryHandler.readMemory(Long.parseLong(parms.get("addr")),Integer.parseInt(parms.get("count"))); + FileOutputStream fo = new FileOutputStream(new File("/sdcard/XServer.dump")); + fo.write(binary); + return "Dumped at /sdcard/XServer.dump"; + case "read": + byte[] bytes=MemoryHandler.readMemory(Long.parseLong(parms.get("addr")),Integer.parseInt(parms.get("count"))); + return bytesToHexString(bytes); + case "write": + MemoryHandler.writeMemory(Long.parseLong(parms.get("addr")),hexStringToBytes(files.get("postData"))); + byte[] bytes_res=MemoryHandler.readMemory(Long.parseLong(parms.get("addr")),hexStringToBytes(files.get("postData")).length); + return bytesToHexString(bytes_res); + default: + return ""; + } + }else{ + HashMap map = new HashMap<>(); + map.put("maps", MemoryHandler.getMaps()); + return XServer.render(map, "pages/memory.html"); + } + } catch (Exception e) { + return e.getLocalizedMessage(); + } + } + + public static String bytesToHexString(byte[] src){ + StringBuffer stringBuffer = new StringBuffer(src.length*2+2); + byte[] hexs = "0123456789ABCDEF".getBytes(); + if (src == null || src.length <= 0) { + return null; + } + for (int i = 0; i < src.length; i++) { + //Log.e("XServer", "bytesToHexString: "+((src[i]&0xFF)>>4)); + //Log.e("XServer", "bytesToHexString: "+((src[i]&0x0F))); + stringBuffer.append((char) (hexs[(src[i]&0xFF)>>4])); + stringBuffer.append((char) (hexs[src[i]&0x0F])); + /* + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuffer.append(0); + } + stringBuffer.append(hv); + */ + } + return stringBuffer.toString(); + } + public static byte[] hexStringToBytes(String hexString) { + if (hexString == null || hexString.equals("")) { + return null; + } + hexString = hexString.toUpperCase(); + int length = hexString.length() / 2; + char[] hexChars = hexString.toCharArray(); + byte[] d = new byte[length]; + for (int i = 0; i < length; i++) { + int pos = i * 2; + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); + } + return d; + } + /** + * Convert char to byte + * @param c char + * @return byte + */ + private static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } +} diff --git a/app/src/main/java/monkeylord/XServer/handler/MemoryHandler.java b/app/src/main/java/monkeylord/XServer/handler/MemoryHandler.java new file mode 100644 index 0000000..22c3b29 --- /dev/null +++ b/app/src/main/java/monkeylord/XServer/handler/MemoryHandler.java @@ -0,0 +1,69 @@ +package monkeylord.XServer.handler; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; + +import de.robv.android.xposed.XposedBridge; +import monkeylord.XServer.XposedEntry; + +public class MemoryHandler { + static HashMap Memory = new HashMap<>(); + static { + try { + // http://androidxref.com/4.4_r1/xref/libcore/luni/src/main/java/libcore/io/Memory.java + Class clzMemory = Class.forName("libcore.io.Memory"); + for (Method m:clzMemory.getDeclaredMethods()) { + Memory.put(m.getName(),m); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + public static byte[] readMemory(long address,int count) throws InvocationTargetException, IllegalAccessException { + if(Memory.get("peekByteArray")==null)throw new IllegalAccessException(); + byte[] data=new byte[count]; + Memory.get("peekByteArray").invoke(null,address, data, 0, count); + return data; + } + public static void writeMemory(long address,byte[] data) throws IllegalAccessException, InvocationTargetException { + if(Memory.get("pokeByteArray")==null)throw new IllegalAccessException(); + byte[] mem = readMemory(address,data.length); + for (int i = 0; i < mem.length; i++) { + if(mem[i]!=data[i]){ + Memory.get("pokeByte").invoke(null,address+i,data[i]); + } + } + //Memory.get("pokeByteArray").invoke(null,address, mem, 0, mem.length); + } + public static String[] getMaps(){ + File maps=new File("/proc/self/maps"); + StringBuilder sb = new StringBuilder(); + try { + FileInputStream is = new FileInputStream(maps); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + String str; + while((str=reader.readLine())!=null){ + sb.append(str+"\r\n"); + } + /* + Process p = Runtime.getRuntime().exec("cat /proc/self/maps"); + p.waitFor(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String str; + while((str=reader.readLine())!=null){ + sb.append(str+"\r\n"); + } + */ + } catch (IOException e) { + e.printStackTrace(); + } + return sb.toString().split("\r\n"); + } + +}