回复
黑皇帝安全网
管理员
管理员
  • 金钱95848枚
  • 威望90274点
  • 贡献值89936点
  • 注册日期2009-09-12
  • 最后登录2019-01-02
  • 荣誉会员
  • VIP会员
  • 社区版主
阅读:1291723回复:821

第三方apk实时获取微信聊天消息记录

楼主#
更多 发布于:2009-09-20 12:00

 

第一步:安装apk的手机进行root

因为需要读取微信聊天记录信息表,所以手机需要root,这样给apk开启更大的权限,这里进行root的工具有好多比如360root大师等相关的root工具。

第二步:用Root Explorer把db文件赋予更高的权限

 

第三步:开始撸代码啦,
由于微信的数据db文件进行加密操作所以咱们这边需要解密
获取手机序列号IMEI号,

public static String getIMEI(Context context) {
TelephonyManager manager = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
if (manager.getDeviceId() != null && manager.getDeviceId().length() > 0) {
return manager.getDeviceId();
} else {
return "";
}
}

获取微信用户信息号需要解析xml,这里解析xml用到的是XmlPullParser进行解析的
这里path路径是:/data/data/com.tencent.mm/shared_prefs/system_config_prefs.xml

public static String getUin(String path) {
try {
FileInputStream inputStream = new FileInputStream(new File(path));
XmlPullParser parser = Xml.newPullParser();
parser.setInput(inputStream, "UTF-8");
int eventType = parser.getEventType();// 产生第一个事件
while (eventType != XmlPullParser.END_DOCUMENT) { //处理事件,不碰到文档结束就一直处理
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
// 不做任何操作或初开始化数据
break;
case XmlPullParser.START_TAG:
// 解析XML节点数据
// 获取当前标签名字
String tagName = parser.getName();
if ("int".equals(parser.getName())) {
String name = parser.getAttributeValue(0);
String value = parser.getAttributeValue(1);
Log.e("int", "name:" + name + ",value:" + value);
return value;
}
break;
case XmlPullParser.END_TAG:
// 单节点完成,可往集合里边添加新的数据
break;
case XmlPullParser.END_DOCUMENT:
break;
}
// 别忘了进入下一个元素并触发相应事件 ,不然就会死循环
eventType = parser.next();
}
} catch (FileNotFoundException e) {
Log.e("FileNotFoundException:", e.toString());
} catch (XmlPullParserException e) {
Log.e("XmlPullParserException:", e.toString());
} catch (IOException e) {
e.printStackTrace();
}
return "";
}

有上面两个字符串计算出打开db的密码,
这里的计算需要用到md5算法进行计算操作先把md5这段代码贴出来
计算密码调用与这几段代码进行配合

String password= (MD5Util.md5(XmlUtil.getIMEI(context)+XmlUtil.getUin("/data/data/com.tencent.mm/shared_prefs/system_config_prefs.xml"))).substring(0,7).toLowerCase();

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* author:
* date: 2016/10/25 20:59
*/
public class MD5Util {

public static final char HEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};

public static String toHexString(byte[] b) { //String to byte
StringBuilder sb = new StringBuilder(b.length * 2);
for (int i = 0; i < b.length; i++) {
sb.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
sb.append(HEX_DIGITS[b[i] & 0x0f]);
}
return sb.toString();
}

public static String md5(String s) {
try {
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();

return toHexString(messageDigest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}

return "";
}
}

拿到密码后可以对数据库的读写进行操作



import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;


/**
* Created by zxf on 2016/10/25.
*/

public class DataHelp {

/**
* 操作数据库读取微信消息
* @param context
* @param path
*/
public static void readWeChatDatabase(Context context,String path) {
SQLiteDatabase.loadLibs(context);

String password= (MD5Util.md5(XmlUtil.getIMEI(context)+XmlUtil.getUin(Constants.uinPath))).substring(0,7).toLowerCase();
Log.e("password", "password:"+password );

SQLiteDatabaseHook hook = new SQLiteDatabaseHook(){
public void preKey(SQLiteDatabase database){
}
public void postKey(SQLiteDatabase database){
database.rawExecSQL("PRAGMA cipher_migrate;"); //最关键的一句!!!
}
};
try {
long time=System.currentTimeMillis();
SQLiteDatabase db = SQLiteDatabase.openDatabase(path, password, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS, hook);
long time2=System.currentTimeMillis();
long time_1=time2-time;
Toast.makeText(context,"time_3:"+time_1, Toast.LENGTH_SHORT).show();
Log.e("readWeChatDatabase", "time_3:"+time_1 );
int count=0;
Cursor c = db.rawQuery("select * from message" , null);
while (c.moveToNext()) {
int _id = c.getInt(c.getColumnIndex("msgId"));
String content= c.getString(c.getColumnIndex("content"));
count++;
Log.e("readWeChatDatabase", "content:"+content );
}
c.close();
db.close();
long time_2=System.currentTimeMillis()-time2;
Toast.makeText(context,"time_4:"+time_2+",count:"+count , Toast.LENGTH_SHORT).show();
Log.e("readWeChatDatabase", "time_4:"+time_2+",count:"+count );
} catch (Exception e) {
Log.e("e", "readWeChatDatabase: "+e.toString() );
}
}
/**
* 复制单个文件
* @param oldPath String 原文件路径 如:c:/fqf.txt
* @param newPath String 复制后路径 如:f:/fqf.txt
* @return boolean
*/
public static void copyFile(Context context,String oldPath, String newPath) {
long time=System.currentTimeMillis();
deleteFolderFile(newPath,true);
long time2=System.currentTimeMillis();
long time_1=time2-time;
Log.e("copyFile", "time_1:"+time_1 );
InputStream inStream=null;
FileOutputStream fs=null;
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) { //文件存在时
inStream = new FileInputStream(oldPath); //读入原文件
fs = new FileOutputStream(newPath);
byte[] buffer = new byte[2048];
while ( (byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
fs.write(buffer, 0, byteread);
}
long time_2=System.currentTimeMillis()-time2;
Log.e("copyFile", "time_2:"+time_2);
readWeChatDatabase(context,newPath);//对copy出来的数据进行操作
}
}catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
}finally {
try {
if (inStream!=null) {
inStream.close();
}
if (fs!=null){
fs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
/**
* 删除指定目录下文件及目录
*
* @param deleteThisPath
* @return
*/
public static void deleteFolderFile(String filePath, boolean deleteThisPath) {
if (!TextUtils.isEmpty(filePath)) {
try {
File file = new File(filePath);
if (file.isDirectory()) {// 处理目录
File files[] = file.listFiles();
for (int i = 0; i < files.length; i++) {
deleteFolderFile(files[i].getAbsolutePath(), true);
}
}
if (deleteThisPath) {
if (!file.isDirectory()) {// 如果是文件,删除
file.delete();
} else {// 目录
if (file.listFiles().length == 0) {// 目录下没有文件或者目录,删除
file.delete();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

在初始activity调用

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.xilexuan.wechatcrack.util.DataHelp;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
Timer timer;
TimerTask mTimerTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
timer = new Timer();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String old_path="/data/data/com.tencent.mm/MicroMsg/b93e23895b9f5b4a8d781ba8d702cfe8/EnMicroMsg.db";
final String new_path="/data/data/copy到你的文件夹下比如com...../EnMicroMsg.db";

DataHelp.copyFile(this,old_path,new_path);
mTimerTask =new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
DataHelp.copyFile(MainActivity.this,old_path,new_path);
}
});
}
};
timer.schedule(mTimerTask, 0, 10000);//10秒一获取
//Toast.makeText(this, pwd, Toast.LENGTH_SHORT).show();
}
}

最后在log内就能看到你截取到的微信聊天记录,这里设置的10秒获取一次。