1. 程式人生 > >MTK平臺手機串號(IMEI)修改

MTK平臺手機串號(IMEI)修改

(1)機型修改:

其實跟安卓系統有關的一些資訊大多在/system/build.prop這個檔案中,尤其是跟機型有關的資訊。下面是ZTE U960S3這臺手機除錯輸出的資訊:


可以看到型號(model),商標(brand),裝置(device),名字(name)等等。修改這些其實是修改build.prop檔案。前面修改MP0B_001也是替換對應檔案。但是安卓系統底層是Linux,/system和/data都需要root許可權才能訪問,或者你原始碼辨析獲得system許可權(這個暫時不談)。程式碼中我有相應的修改許可權的函式,以chmod開頭的函式,修改相應的檔案許可權,我們可以對之進行修改、替換操作,達到我們的目的。當然,IMEI和機型等的資訊需要修改才能生效。

如果您需要修改build.prop的其他資訊,izai我的程式碼基礎之上新增其他修改,比如mac地址的等。強烈建議您備份一份build.prop檔案,備份的操作可以通過adb shell進行操作,比如上面我備份的檔案叫build.back。一旦build.prop檔案損壞,我們可以替換回去。

(2)重點說一下檔案存放位置:

1. MP0B_001*的系列檔案需要存放在SD卡根目錄的imei資料夾中,檔名可以變(不是MP0B_001*),但是不能有其他不包含imei資訊的檔案,否者替換無效,copy檔案到imei資料夾的時候請留意是否有無效檔案。

2. 包含機型資訊的檔案需要放置SD卡根目錄,檔名為model.txt 。此檔案的資訊每一行含有兩個部分:手機品牌+型號,比如:lenovo A750.中間有一個空格,每一行只有手機品牌和型號之間有空格 多出來的空格無效,多出空格活菏澤無空格會報異常。請輸入資訊的時候注意是否按要求錄入。

關於開機自啟動,已經完成,預設會有10s提示。點選取消按鈕取消自動寫入及重啟,變成手動模式。否則軟體自動寫入新的imei和機型資訊然後重新啟動,迴圈下去。下面是修改的結果的部分截圖:


(3)軟體介面如下:


其中imei1和imei2分別是兩個卡對應的imei號,imeis為我們將要替換系統MP0B_001檔案的檔名。PC端生成的MP0B_001*檔案請拷貝到安卓手機的SD卡的根目錄的imei資料夾中。一般是/sdcard/imei路徑,注意此資料夾中不要拷貝其他無關檔案,寫入時預設選取改目錄下的第一個檔案,寫入完成會刪除相應檔案。重啟按鈕就是重啟手機了,也可以改成寫入完成後立即重啟。


(4)相關程式碼如下:

package com.org.mtk_imei_app;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.*;

public class MainActivity extends Activity {

	private EditText imeisEdittext = null;
	private EditText imei1Edittext = null;
	private EditText imei2Edittext = null;
	private EditText modelEdittext = null;

	private Button startWriteBtn = null;
	private Button restartBtn = null;

	int mNegativeCount = 100;
	final int TYPE_COUNTERDOWN_COUNTER = 11;
	AlertDialog.Builder counterDownDialog;
	TextView textView = null;
	private boolean stopHandler = false;
	private int delayTime = 10;

	private String TAG = "APP";
	private String targetImeiDir = "/data/nvram/md/NVRAM/NVD_IMEI/";
	private String targetImeiName = targetImeiDir + "MP0B_001";

	private String imeiDataDir = "imei";
	private String tempFilename = "";
	private String dataNvram = "/data/nvram";
	private String modelDataFile = "model.txt";
	private String typeDataFileDir = "/system/build.prop";
	private String tempTypeDataFileDir = "/system/tempbuild.prop";
	
	private String name = "";
	private String model = "";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		imei1Edittext = (EditText)findViewById(R.id.imei1Edittext);
		imei2Edittext = (EditText)findViewById(R.id.imei2Edittext);
		imeisEdittext = (EditText)findViewById(R.id.imeisEdittext);
		modelEdittext = (EditText)findViewById(R.id.modelEdittext);

		startWriteBtn = (Button)findViewById(R.id.startWrite);
		restartBtn = (Button)findViewById(R.id.restart);


		startWriteBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {	
				startWriteBtn.setEnabled(false);
				writeImei();
				try {
					writeModel();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				restoreNVRamImei(dataNvram); 
				restoreNVRamImei(typeDataFileDir);
				restartBtn.setEnabled(true);
			}
		});

		restartBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {	
				restart();
			}

		});

	}


	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();

		if(!isRoot()){	
			AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this);
			mDialog.setTitle("警告!");
			mDialog.setMessage("您的手機沒有root,程式將自動退出!請root重新操作!");
			mDialog.setPositiveButton("確定",
					new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					finish();
				}
			}).show();
		}

		if(!isImeiDataExist()){
			AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this);
			mDialog.setTitle("錯誤!");
			mDialog.setMessage("SD卡imei目錄為空或者不存在!程式將退出!");
			mDialog.setPositiveButton("確定",
					new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					finish();
				}
			}).show();
		}

		chmodNVRamImei(dataNvram);
				
		if  (!isExist(targetImeiDir)){     
			AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this);
			mDialog.setTitle("錯誤!");
			mDialog.setMessage("抱歉,不支援您的手機!您的手機沒有/data/nvram/md/NVRAM/NVD_IMEI/目錄或者已損壞!");
			mDialog.setPositiveButton("確定",
					new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					finish();
				}
			}).show();
		}
		getSIMInfo();

		chmodNVRamImei(typeDataFileDir);
		try {
			if(!isModelDataExist()){
				AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this);
				mDialog.setTitle("錯誤!");
				mDialog.setMessage("機型資料檔案model.txt不錯在!");
				mDialog.setPositiveButton("確定",
						new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						finish();
					}
				}).show();
				
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		autoInit();

		startWriteBtn.setEnabled(true);
	}	


	private void chmodNVRamImei(String targetImeiDir)
	{

		if(isRoot()){
			java.lang.Process process;
			try {
				process = Runtime.getRuntime().exec("su");
				DataOutputStream os = new DataOutputStream(process.getOutputStream());
				String command = "chmod -R 777 "+targetImeiDir+"\n";
				os.writeBytes(command);
				os.writeBytes("exit\n");
				os.flush();
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{
			Log.i(TAG,"The target directory has not been root."); 
		}
	}

	private void restoreNVRamImei(String targetImeiDir)
	{

		if(isRoot()){
			java.lang.Process process;
			try {
				process = Runtime.getRuntime().exec("su");
				DataOutputStream os = new DataOutputStream(process.getOutputStream());
				String command = "chmod -R 771 "+targetImeiDir+"\n";
				os.writeBytes(command);
				os.writeBytes("exit\n");
				os.flush();
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{
			Log.i(TAG,"The target directory has not been root."); 
		}
	}

	public boolean isRoot(){
		boolean bool = false;

		try{
			if ((!new File("/system/bin/su").exists()) && (!new File("/system/xbin/su").exists())){
				bool = false;
			} else {
				bool = true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return bool;
	}


	public boolean isExist(String filePath) {
		//		String paths[] = filePath.split("/");
		//		String dir = paths[0];
		//		for (int i = 0; i < paths.length - 1; i++) {
		//			dir = dir + "/" + paths[i + 1];
		//			Log.i(TAG,"dir:  "+dir); 
		//			File dirFile = new File(dir);
		//			if (!dirFile.exists()) {
		//				return false;
		//			}
		//		}

		return true;
	}

	public boolean isImeiDataExist(){
		File sdDir = null; 
		boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);   //判斷sd卡是否存在 
		if(sdCardExist)   
		{                               
			sdDir = Environment.getExternalStorageDirectory(); 
		}else{
			return false;
		}

		tempFilename = sdDir+"/"+ imeiDataDir;
		File dirFile = new File(tempFilename);
		if (!dirFile.exists()) {
			return false;
		}else if(dirFile.list().length == 0){
			return false;
		}

		String filename = dirFile.list()[0];
		File temp = new File(filename);
		imeisEdittext.setText(temp.getName());

		return true;
	}
	
	public boolean isModelDataExist() throws IOException{
		File sdDir = null; 
		boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);   //判斷sd卡是否存在 
		if(sdCardExist)   
		{                               
			sdDir = Environment.getExternalStorageDirectory(); 
		}else{
			return false;
		}

		tempFilename = sdDir+"/"+ modelDataFile;
		File dirFile = new File(tempFilename);
		if (!dirFile.exists()) {
			return false;
		}else if(dirFile.length()==0){
			return false;
		}

		BufferedReader readerSD = null;
		List<String> listSD = new ArrayList<String>();
		readerSD = new BufferedReader(new FileReader(dirFile));
		String textSD = readerSD.readLine();
		while (textSD != null) {
			listSD.add(textSD);
			textSD = readerSD.readLine();
		}
		readerSD.close();
		
		Calendar calendar = Calendar.getInstance();
		int num = (calendar.get(Calendar.MINUTE)*60+calendar.get(Calendar.SECOND))%listSD.size();
		Log.i(TAG,"num: "+num+"listSD.size()"+listSD.size());
		String modelAndNameString = listSD.get(num);
		modelEdittext.setText(modelAndNameString);
		
		model = modelAndNameString.split(" ")[0];
		name = modelAndNameString.split(" ")[1];
		
		return true;
	}
	
	private void writeModel() throws IOException{

		File file = new File(typeDataFileDir);
		if(!file.exists()){
			AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this);
			mDialog.setTitle("錯誤!");
			mDialog.setMessage("抱歉,您的手機不支援修改機型!");
			mDialog.setPositiveButton("確定",
					new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					finish();
				}
			}).show();
		}
		
		BufferedReader reader = null;
		List<String> list = new ArrayList<String>();
		reader = new BufferedReader(new FileReader(file));
		String text = reader.readLine();
		while (text != null) {
			if(text.contains("ro.product.model")){
				text = "ro.product.model="+model+" "+name;
			}else if(text.contains("ro.product.brand")){
				text = "ro.product.brand="+model;
			}else if(text.contains("ro.product.name")){
				text = "ro.product.name="+name;
			}else if(text.contains("ro.product.manufacturer")){
				text = "ro.product.manufacturer="+model;
			}else if(text.contains("ro.product.device")){
				text = "ro.product.device="+name;
			}else if(text.contains("ro.product.board")){
				text = "ro.product.board="+name;
			}else if(text.contains("ro.product.customize")){
				text = "ro.product.customize="+name;
			}
			list.add(text+"\n\r");
			text = reader.readLine();
		}
		reader.close();

		FileOutputStream outputStream = new FileOutputStream(file);
		for (String s : list) {
			outputStream.write(s.getBytes());
		}
		outputStream.close();
		
			
	}


	private void writeImei(){
		File dirFile = new File(Environment.getExternalStorageDirectory()+"/"+imeiDataDir);
		String filename = dirFile.list()[0];

		File temp = new File(Environment.getExternalStorageDirectory()+"/"+imeiDataDir+"/"+filename);
		File targetFile = new File(targetImeiName);
		if (targetFile.exists()) {
			targetFile.delete();
		}

		InputStream in = null;;
		try {
			in = new FileInputStream(temp);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		OutputStream out = null;
		try {
			out = new FileOutputStream(targetFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		byte[] buf = new byte[1024];
		int len;
		try {
			while ((len = in.read(buf)) !=-1) {
				try {
					out.write(buf, 0, len);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			out.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			in.close();
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if (temp.exists()) {
			temp.delete();
		}
	}

	public void autoInit(){		
		TimerDialog dialog = new TimerDialog(MainActivity.this);
		dialog.setTitle("注意!");
		dialog.setMessage("程式將自動執行!");
		dialog.setPositiveButton("取消", new DialogInterface.OnClickListener()
		{

			@Override
			public void onClick(DialogInterface dialog, int which)
			{
				stopHandler = true;
			}
		}, delayTime);
		dialog.show();
		dialog.setButtonType(Dialog.BUTTON_POSITIVE, delayTime, true);
	}

	public void restart() {
		try {
			Process process = Runtime.getRuntime().exec("su");
			DataOutputStream out = new DataOutputStream(
					process.getOutputStream());
			out.writeBytes("reboot \n");
			out.writeBytes("exit\n");
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private  void getSIMInfo() {
		try {
			TelephonyManager tm =  (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);  
			Class<?> c = Class.forName("com.android.internal.telephony.Phone");
			Field fields1 = c.getField("GEMINI_SIM_1");
			fields1.setAccessible(true);
			Integer simId_1 = (Integer) fields1.get(null);
			Field fields2 = c.getField("GEMINI_SIM_2");
			fields2.setAccessible(true);
			Integer simId_2 = (Integer) fields2.get(null);

			Method m = TelephonyManager.class.getDeclaredMethod(
					"getSubscriberIdGemini", int.class);


			Method m1 = TelephonyManager.class.getDeclaredMethod(
					"getDeviceIdGemini", int.class);
			String imei_1 = (String) m1.invoke(tm, simId_1);
			String imei_2 = (String) m1.invoke(tm, simId_2);

			Log.i(TAG,"imei_1: "+imei_1);
			Log.i(TAG,"imei_2: "+imei_2);

			imei1Edittext.setText(imei_1);
			imei2Edittext.setText(imei_2);


		} catch (Exception e) {
			return;
		}
	}

	public class TimerDialog{

		private static final int TYPE_POSITIVE = 1;
		private static final int TYPE_NEGATIVE = 2;

		private Context mContext;
		private Button p = null;
		private Button n = null;    
		private int mPositiveCount = 0;
		private int mNegativeCount = 0;
		private AlertDialog mDialog = null;

		public TimerDialog(Context ctx){
			mContext = ctx;

			mDialog = new AlertDialog.Builder(mContext).create();
		}	

		public void setMessage(String msg){
			mDialog.setMessage(msg);
		}

		public void setTitle(int resId){
			mDialog.setTitle(resId);
		}

		public void setTitle(String title){
			mDialog.setTitle(title);
		}

		public void show(){
			mDialog.show();

		}

		public void setPositiveButton(String text, DialogInterface.OnClickListener listener, int count){
			text = getTimeText(text, count);
			mDialog.setButton(Dialog.BUTTON_POSITIVE, text, listener);
		}

		public void setNegativeButton(String text, DialogInterface.OnClickListener listener, int count){
			text = getTimeText(text, count);
			mDialog.setButton(Dialog.BUTTON_NEGATIVE, text, listener);
		}


		public void setButtonType(int type, int count, boolean isDisable){

			if(count <= 0){
				return;
			}

			if(type == Dialog.BUTTON_POSITIVE){			
				p = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);
				p.setEnabled(isDisable);
				mPositiveCount = count;
				mHandler.sendEmptyMessageDelayed(TYPE_POSITIVE, 200);
			}else{
				if(type == Dialog.BUTTON_NEGATIVE){				
					n = mDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
					n.setEnabled(isDisable);
					mNegativeCount = count;
					mHandler.sendEmptyMessageDelayed(TYPE_NEGATIVE, 200);
				}
			}
		}

		private Handler mHandler = new Handler(){

			public void handleMessage(Message msg){

				switch(msg.what){
				case TYPE_NEGATIVE:       		
					if(mNegativeCount > 0){
						mNegativeCount--;
						if(n != null){
							String text = (String) n.getText();
							n.setText(getTimeText(text, mNegativeCount));
						}
						mHandler.sendEmptyMessageDelayed(TYPE_NEGATIVE, 1000);
					}else{

						if(n != null){
							if(n.isEnabled()){
								n.performClick();
							}else{
								n.setEnabled(true);
							}
						}
					}
					break;
				case TYPE_POSITIVE:
					if(mPositiveCount > 0){
						mPositiveCount--;
						if(p != null){
							String text = (String) p.getText();
							p.setText(getTimeText(text, mPositiveCount));
						}
						if(stopHandler){
							mHandler.removeMessages(TYPE_POSITIVE);
							return ;
						}
						mHandler.sendEmptyMessageDelayed(TYPE_POSITIVE, 1000);
					}else{

						if(p != null){
							if(p.isEnabled()){
								p.performClick();
							}else{
								p.setEnabled(true);
							}
						}

						writeImei();
						restart();
						try {
							writeModel();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					break;
				}
			}
		};


		private String getTimeText(String text, int count){
			if(text != null && text.length() > 0 && count > 0){
				int index = text.indexOf("(");
				if(index > 0){
					text = text.substring(0, index);
					return (text + "("+count+"s)");
				}else{
					return (text + "("+count+"s)");
				}
			}
			return text;
		}
	}
}