读取AXML二进制流修改DEMO

来源:互联网 发布:matlab矩阵中字母 编辑:程序博客网 时间:2024/06/05 15:12

很重要的参考博客:http://blog.csdn.net/jiangwei0910410003/article/details/50568487 

在此感谢原作者

本DEMO目标为隐藏APP启动图标。

方法为修改AXML文件中<category android:name="android.intent.category.LAUNCHER"/>至<category android:name="android.intent.category.DEFAULT"/>同时修改各项参数:

文件大小段,字符串数目,字符串偏移量,字符串chunk参数,字符串段开始位置偏移量。

注意:

修改AXML文件后要重新签名

最后的文件一定要4位对齐不然会导致APP无法安装

代码如下:

package cn.com.silence;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;public class MainClass {/** * 用来保存所有的字符串,在xmlcontent里会调用 */public static ArrayList<String> stringList = new ArrayList<String>();/** * 存储所有的resouceID暂时没用上 */private static ArrayList<Integer> resIdList = new ArrayList<Integer>();/** * android.intent.category数据段 */private static final byte[] CATEGOTY = new byte[] { 0x20, 0x00, 0x61, 0x00,0x6E, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x69, 0x00, 0x64,0x00, 0x2E, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x65, 0x00,0x6E, 0x00, 0x74, 0x00, 0x2E, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74,0x00, 0x65, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00,0x2E, 0x00, 0x4c, 0x00, 0x41, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x43,0x00, 0x48, 0x00, 0x45, 0x00, 0x52, 0x00, 0x00, 0x00 };/** * android.intent.DEFAULT数据段后面的0是用来4位对齐,文件不是4的整数倍无法安装 */private static final byte[] DEFAULT = new byte[] { 0x1F, 0x00, 0x61, 0x00,0x6E, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x69, 0x00, 0x64,0x00, 0x2E, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x65, 0x00,0x6E, 0x00, 0x74, 0x00, 0x2E, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74,0x00, 0x65, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00,0x2E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x41, 0x00, 0x55,0x00, 0x4c, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00 };/** * categroy数据段长度 */private static final int CATEGORYLENGTH = CATEGOTY.length;/** * category string字段位置 */private static int categoryPosition = -1;/** * string段结束位置 */private static int stringEndPosition;/** * 偏移量段结束位置 */private static int stringStartPosition;/** * category后string段偏移量 *///private static ArrayList<HashMap<String, Integer>> laterStringOffset;private static int xmlSize;private static byte[] xmlData;/** * 修改xmlcontent段中,category块里参数对应value的指向stringlist的值,即从launcher重新指向default *  * @param pos tag中value所在的位置 */private static void modifyContent(int pos) {byte[] buffer = Utils.intToByte(stringList.size());System.arraycopy(buffer, 0, xmlData, pos, 4);System.out.println("Content modify finished...");}/** * 修改文件大小 */private static void modifyFileSize() {System.out.println(xmlSize);byte[] sizeData = Utils.intToByte(xmlSize);System.arraycopy(sizeData, 0, xmlData, 4, 4);System.out.println("file size modified...");}/** * 修改字符串端开始前的参数 */private static void modifyOffset() {byte[] stringCount = new byte[4];System.arraycopy(xmlData, 16, stringCount, 0, 4);int lastStringOffset = 36 + Utils.byteToInt(stringCount) * 4;stringCount = Utils.intToByte(Utils.byteToInt(stringCount) + 1);System.arraycopy(stringCount, 0, xmlData, 16, 4);// string count + 1byte[] newStringChunkSize = new byte[4];System.arraycopy(xmlData, 12, newStringChunkSize, 0, 4);newStringChunkSize = Utils.intToByte(Utils.byteToInt(newStringChunkSize) + DEFAULT.length + 4);System.arraycopy(newStringChunkSize, 0, xmlData, 12, 4);// stringChunkSize// + 72int z = stringStartPosition - 8 + 4;byte[] newStringStartOffset = Utils.intToByte(z);System.arraycopy(newStringStartOffset, 0, xmlData, 28, 4);// string// start// pos++byte[] temp = new byte[xmlSize + 4];byte[] nStringOffset = Utils.intToByte(stringEndPosition- stringStartPosition - DEFAULT.length);// add new offsetSystem.arraycopy(xmlData, 0, temp, 0, lastStringOffset);System.arraycopy(nStringOffset, 0, temp, lastStringOffset, 4);System.arraycopy(xmlData, lastStringOffset, temp, lastStringOffset + 4,xmlSize - lastStringOffset);xmlSize = xmlSize + 4;xmlData = new byte[xmlSize];System.arraycopy(temp, 0, xmlData, 0, xmlSize);stringEndPosition += 4;System.out.println("offset modify finished...");}/** * 增加android.intent.category.default字符串 */private static void modifyString() {byte[] temp = new byte[xmlSize + DEFAULT.length];System.arraycopy(xmlData, 0, temp, 0, stringEndPosition);System.arraycopy(DEFAULT, 0, temp, stringEndPosition, DEFAULT.length);System.arraycopy(xmlData, stringEndPosition, temp, stringEndPosition+ DEFAULT.length, xmlSize - stringEndPosition);stringEndPosition += DEFAULT.length;xmlSize = xmlSize + DEFAULT.length;xmlData = new byte[xmlSize];System.arraycopy(temp, 0, xmlData, 0, xmlSize);}/** * 获取string段结束的位置 * @param data 二进制axml文件 * @return 位置 */private static int getEndPosition(byte[] data) {int i = 0;byte[] temp = new byte[4];System.arraycopy(data, 12, temp, 0, 4);i = Utils.byteToInt(temp);i = i + 8;return i;}/** * 一大堆里最后用上的只有string偏移量段结束的位置——字符串段开始的位置 * @param data AXML二进制文件 */private static void getCategory(byte[] data) {//int i = -1;byte[] tempNum = new byte[4];System.arraycopy(data, 28, tempNum, 0, 4);stringStartPosition = Utils.byteToInt(tempNum) + 8;// 偏移量段结束位置System.out.println("string off set position: " + stringStartPosition);byte[] temp = new byte[CATEGORYLENGTH];for (int j = 36; j < stringStartPosition; j += 4) {System.arraycopy(data, j, tempNum, 0, 4);int stringOffset = Utils.byteToInt(tempNum) + stringStartPosition;// System.out.println(stringOffset);System.arraycopy(data, stringOffset, temp, 0, CATEGORYLENGTH);if (Arrays.equals(temp, CATEGOTY)) {categoryPosition = stringOffset;break;}}}public static void main(String[] args) throws Exception {FileInputStream fis = new FileInputStream(new File("E:/AndroidManifest.xml"));xmlSize = fis.available();xmlData = new byte[xmlSize];fis.read(xmlData, 0, xmlSize);fis.close(); stringEndPosition = getEndPosition(xmlData);System.out.println("StringChunk end position: " + stringEndPosition);getCategory(xmlData);// category位置if (categoryPosition == -1) {System.out.println("Category not found");Runtime.getRuntime().exit(0);}System.out.println("category string position: " + categoryPosition);System.out.println("string start pos: " + stringStartPosition);System.out.println("string end pos: " + stringEndPosition);stringList = ReadData.strings(xmlData, stringStartPosition);resIdList = ReadData.resID(xmlData, stringEndPosition);//int count = 0;int pos = 0;modifyString();modifyOffset();Find find = new Find(xmlData, stringEndPosition);pos = find.getPosition();byte[] buffer = new byte[4];System.arraycopy(xmlData, pos + 44, buffer, 0, 4);System.out.println("valueString = "+ stringList.get(Utils.byteToInt(buffer)));modifyContent(pos + 44);modifyFileSize();FileOutputStream fos = new FileOutputStream(new File("E:/AndroidManifest.xml"));fos.write(xmlData, 0, xmlSize);fos.flush();fos.close();System.out.println("All finished....");}}

下面这个类用于读取string和resourceID

package cn.com.silence;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;public class ReadData {public static ArrayList<String> strings(byte[] data, int stringOffsetPosition){ArrayList<String> stringList = new ArrayList<String>();byte[] tempNum = new byte[4];byte[] string;System.out.println("********************Strings below***********************");for (int j = 36; j < stringOffsetPosition; j += 4) {System.arraycopy(data, j, tempNum, 0, 4);int stringOffset = Utils.byteToInt(tempNum) + stringOffsetPosition;tempNum = new byte[]{0, 0, 0, 0};System.arraycopy(data, stringOffset, tempNum, 0, 2);int stringLength = Utils.byteToInt(tempNum);string = new byte[stringLength * 2];System.arraycopy(data, stringOffset + 2, string, 0, string.length);byte[] printUse = new byte[stringLength];for (int i = 0; i < stringLength; i++) {System.arraycopy(string, i * 2, printUse, i, 1);}System.out.println(new String(printUse));stringList.add(new String(printUse));}System.out.println("********************Strings finished***********************");return stringList;}public static ArrayList<Integer> resID(byte[] data, int startPos){byte[] sizeData = new byte[4];byte[] idData = new byte[4];System.arraycopy(data, startPos + 4, sizeData, 0, 4);int size = Utils.byteToInt(sizeData);ArrayList<Integer> resourceIdList = new ArrayList<Integer>(size - 2);System.out.println("********************resID below***********************");System.arraycopy(data, startPos, idData, 0, 4);System.out.println("start data: " + Arrays.toString(idData) + "\nsize: " + size);for (int i = 0; i  < (size - 8); i += 4) {System.arraycopy(data, startPos + 8 + i, idData, 0, 4);int resID = Utils.byteToInt(idData);System.out.println("id: "+ resID + ", hex: " + Arrays.toString(idData));resourceIdList.add(resID);}System.out.println("********************resID finished***********************");return resourceIdList;}}

package cn.com.silence;public class Utils {public static int byteToInt(byte[] buffer) {int i = (((buffer[3] << 24) & 0xff000000)| ((buffer[2] << 16) & 0xff0000) | ((buffer[1] << 8) & 0xff00) | ((buffer[0]) & 0xff));return i;}public static byte[] intToByte(int i) {byte[] buffer = new byte[4];buffer[3] = (byte) (((i) >> 24) & 0xff);buffer[2] = (byte) (((i) >> 16) & 0xff);buffer[1] = (byte) (((i) >> 8) & 0xff);buffer[0] = (byte) ((i) & 0xff);return buffer;}}
下面这个类用于查找<category android:name="android.intent.category.LAUNCHER"/>字段在xmlcontent的位置,并返回
package cn.com.silence;import java.util.Arrays;public class Find {private int position = 0;private int output = -1;private byte[] data;private final byte[] tagBegin = { 0x02, 0x01, 0x10, 0x00 };private final byte[] tagEnd = { 0x03, 0x01, 0x10, 0x00 };public Find(byte[] b, int pos) {data = b;int count = 0;for (position = pos; position + 5 < data.length; position++) {if (tagStart()) {count++;if (count == 5 && check()) {output = position;System.out.println("xmlContent Category Position:  "+ position);break;}} else if (tagEnd()) {count--;}}}private boolean check() {byte[] buffer = new byte[4];System.arraycopy(data, position + 20, buffer, 0, 4);byte[] buffer1 = new byte[4];System.arraycopy(data, position + 44, buffer1, 0, 4);System.out.println(position);System.out.println(Utils.byteToInt(buffer) + "###############################"+ MainClass.stringList.get(Utils.byteToInt(buffer)).equals("category"));System.out.println(Utils.byteToInt(buffer1) + "###############################"+ MainClass.stringList.get(Utils.byteToInt(buffer1)).equals("android.intent.category.LAUNCHER"));if (MainClass.stringList.get(Utils.byteToInt(buffer)).equals("category")&& MainClass.stringList.get(Utils.byteToInt(buffer1)).equals("android.intent.category.LAUNCHER")) {return true;} else {return false;}}private boolean tagStart() {byte[] a = new byte[4];System.arraycopy(data, position, a, 0, 4);if (Arrays.equals(a, tagBegin)) {return true;} else {return false;}}private boolean tagEnd() {byte[] a = new byte[4];System.arraycopy(data, position, a, 0, 4);if (Arrays.equals(a, tagEnd)) {return true;} else {return false;}}public int getPosition() {return output;}}



0 0
原创粉丝点击