(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 listSD = new ArrayList();
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 list = new ArrayList();
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;
}
}
}