欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]破解微信数据库 并查询好友总人数

[原创]破解微信数据库 并查询好友总人数

 

由于工作需求破解了微信数据库 并获取想要的信息上传服务器 都是内部手机   网上大神反编译了微信 发现微信的数据库是通过

手机的IMEI(唯一识别码) + UIN  大写的IMEI + UIN 进行MD5加密 取32位小写 的前7位就是破解数据库的密码 

这是核心原理 根据这个 可以手动获取IMEI 加上UIN 通过 http://tool.chinaz.com/Tools/MD5.aspx线上加密  

手动破解不用写代码这种 

IMEI 应该不用我说 设置里自己去看  下载三方软件也可以看  

 至于 UIN 是在  data data com.tencent.mm  shared_prefs 文件里的 

aunt_info_key_prefs.xml  在这个文件里的 value 值就是了 我们要找到Uin

还有一个问题 网上提及的很少  微信的数据库加密是通过getDeviceID 这个函数会随机获取 IMEI 1  IMEI2 和MEID 进行加密 我已经确认了

肯定不会获取 IMEI2  只会通过默认卡1 IMEI1 和MEID进行 加密  如果破解失败可以用MEID 尝试进行破解  我在下面的连接数据库那做了这个机制

失败就走 MEID试一遍  MEID无法直接获取 我们都是手动获取的把MEID放在文件里 进行读取



接下来就是写代码了  微信数据库也是比较火 网上资料不少的  我也是参考了好多 

public static final String WX_ROOT_PATH = "/data/data/com.tencent.mm/";

// U ID 文件路径

private static final String WX_SP_UIN_PATH = WX_ROOT_PATH + "shared_prefs/auth_info_key_prefs.xml";

private String mDbPassword;

// 提交参数

private int  count=0;

private String IMEI;

private String Uin;

private static final String WX_DB_DIR_PATH = WX_ROOT_PATH + "MicroMsg";

private List<File> mWxDbPathList = new ArrayList<>();

private static final String WX_DB_FILE_NAME = "EnMicroMsg.db";

private String mCurrApkPath = "/data/data/" + MyApplication.getContextObject().getPackageName() + "/";

private static final String COPY_WX_DATA_DB = "wx_data.db";

// 我是放在了服务里     做了延迟每隔一个小时破解一次 可以去掉

public void onCreate() {   

 super.onCreate();  

   // 获取root权限  

   execRootCmd("chmod -R 777 " + WX_ROOT_PATH);

    execRootCmd("chmod  777 /data/data/com.tencent.mm/shared_prefs/auth_info_key_prefs.xml");

  Toast.makeText(this,"开启服务",Toast.LENGTH_LONG).show();

    Timer timer = new Timer();

     timer.schedule(new TimerTask() {     

         @Override  

            public void run() {            

      // 获取微信的U id            

       initCurrWxUin();           

         //sqlt= (EditText) findViewById(sqlt);         

             // 获取 IMEI 唯一识别码          

                TelephonyManager phone = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);  

                           IMEI = phone.getDeviceId();

             System.out.println("IMEI"+IMEI);           

               // 根据imei和uin生成的md5码,获取数据库的密码(去前七位的小写字母)           

                 initDbPassword(IMEI, Uin);

             System.out.println(mDbPassword + "数据库的密码");

             System.out.println("开始统计好友数量");          

                //  递归查询微信本地数据库文件            

                 File wxDataDir = new File(WX_DB_DIR_PATH);        

                      mWxDbPathList.clear();

            searchFile(wxDataDir, WX_DB_FILE_NAME);

             System.out.println("查询数据库文件");

             System.out.println(mWxDbPathList+"读取到的数据库");         

               try {                                     

                 //处理多账号登陆情况    

                        // 这里要注意 微信登陆多个账号会产生 多个数据库文件 

                     // 所有我们需要把每个数据库文件都尝试破解一下 总有一个密码正确连接成功

                   // 有需要可以把注释解开   

                  //  现在的写法是取集合遍历出来的数据库最后一个 我发现遍历的函数很大几率从老文件开是遍历

                   // 最后遍历的db 数据库很可能是新的 也就是当前账号的 但并不稳定 因为这个函数并没有解释

                   //   是从老的开始遍历  两个数据库的情况下 最后一个数据库确实是新的             

     // for (int i = 0; i < mWxDbPathList.size(); i++) {           

            File file = mWxDbPathList.get(mWxDbPathList.size()-1);         

                    File file = mWxDbPathList.get(i); // 正常写法             

                             String copyFilePath = mCurrApkPath + COPY_WX_DATA_DB;              

        //将微信数据库拷贝出来,因为直接连接微信的db,会导致微信崩溃  当前数据库只能连接一个    

                        copyFile(file.getAbsolutePath(), copyFilePath);               

           File copyWxDataDb = new File(copyFilePath);              

         openWxDb(copyWxDataDb);      

  //  }

 

      }catch (Exception e){      

        // Toast.makeText(getApplicationContext(),"解析失败",Toast.LENGTH_LONG).show();    

          }       

           // 上传统计数据      

             login();

    }

}, 1000, 3600000);//0是延时;100是间隔

 相关工具类  直接复制就行   环境复制就

------------------------------------------------------------------------------------------

/** * 执行linux指令 * * @param paramString */

public void execRootCmd(String paramString) {  

  try {

        Process localProcess = Runtime.getRuntime().exec("su");

        Object localObject = localProcess.getOutputStream();

        DataOutputStream localDataOutputStream = new DataOutputStream((OutputStream) localObject);

        String str = String.valueOf(paramString);

        localObject = str + "\n";

        localDataOutputStream.writeBytes((String) localObject);

        localDataOutputStream.flush();

        localDataOutputStream.writeBytes("exit\n");

        localDataOutputStream.flush();

        localProcess.waitFor();

        localObject = localProcess.exitValue();

    } catch (Exception localException) {

        localException.printStackTrace();

    }

}

/** * 获取微信的uid * 微信的uid存储在SharedPreferences里面 * 

存储位置\data\data\com.tencent.mm\shared_prefs\auth_info_key_prefs.xml */private void initCurrWxUin() 

{    Uin = null;

    File file = new File(WX_SP_UIN_PATH);  

      try {

        FileInputStream in = new FileInputStream(file);

        SAXReader saxReader = new SAXReader();

        Document document = saxReader.read(in);

        Element root = document.getRootElement();

        List<Element> elements = root.elements();      

          for (Element element : elements) {           

           if ("_auth_uin".equals(element.attributeValue("name"))) {   

                        Uin = element.attributeValue("value");

            }

        }

    } catch (Exception e) {

        e.printStackTrace();

        LogUtil.e("获取微信uid失败,请检查auth_info_key_prefs文件权限");

    }

}/** * 根据imei和uin生成的md5码,获取数据库的密码(去前七位的小写字母) * * @param imei * @param uin * @return */

private void initDbPassword(String imei, String uin) {  

  if (TextUtils.isEmpty(imei) || TextUtils.isEmpty(uin)) {

  

        LogUtil.e("初始化数据库密码失败:imei或uid为空");     

           return;

    }

    String md5 = getMD5(imei + uin);

    System.out.println(imei+uin+"初始数值");

    System.out.println(md5+"MD5");

    String password = md5.substring(0, 7).toLowerCase();

    System.out.println("加密后"+password);  

      mDbPassword = password;

}

public String getMD5(String info)

{    try    {

        MessageDigest md5 = MessageDigest.getInstance("MD5");

        md5.update(info.getBytes("UTF-8"));     

           byte[] encryption = md5.digest();

        StringBuffer strBuf = new StringBuffer();    

            for (int i = 0; i < encryption.length; i++)

            

        {            if (Integer.toHexString(0xff & encryption[i]).length() == 1)

            {

                strBuf.append("0").append(Integer.toHexString(0xff & encryption[i]));

            }    else {

                strBuf.append(Integer.toHexString(0xff & encryption[i]));

            }

        }        return strBuf.toString();

    }    catch (NoSuchAlgorithmException e)

    {        return "";

    }    catch (UnsupportedEncodingException e)

    {        return "";

    }

}/** * md5加密 * * @param content * @return */

private String md5(String content) {

    MessageDigest md5 = null;  

      try {

        md5 = MessageDigest.getInstance("MD5");

        md5.update(content.getBytes("UTF-8"));   

             byte[] encryption = md5.digest();//加密     

                StringBuffer sb = new StringBuffer();     

                   for (int i = 0; i < encryption.length; i++) {   

                            if (Integer.toHexString(0xff & encryption[i]).length() == 1) {

                sb.append("0").append(Integer.toHexString(0xff & encryption[i]));

            } else {

                sb.append(Integer.toHexString(0xff & encryption[i]));

            }

        }        return sb.toString();

    } catch (Exception e) {

        e.printStackTrace();     

           return null;

    }

}

/** * 递归查询微信本地数据库文件 * * @param file     目录 * @param fileName 需要查找的文件名称 *

/private void searchFile(File file, String fileName) {   

 // 判断是否是文件夹    if (file.isDirectory()) {      

   // 遍历文件夹里所有数据        

   File[] files = file.listFiles();     

      if (files != null) {         

         for (File childFile : files) {

                searchFile(childFile, fileName);

            }

        }

    } else {     

       if (fileName.equals(file.getName())) {    

               mWxDbPathList.add(file);

        }

    }

}/** * 复制单个文件 * * @param oldPath String 原文件路径 如:c:/fqf.txt * @param newPath String 复制后路径 如:f:/fqf.txt * @return boolean */

public void copyFile(String oldPath, String newPath) { 

   try {        int byteRead = 0;

        File oldFile = new File(oldPath);      

          if (oldFile.exists()) { //文件存在时        

              InputStream inStream = new FileInputStream(oldPath); //读入原文件   

                       FileOutputStream fs = new FileOutputStream(newPath);      

                     byte[] buffer = new byte[1444];          

                       while ((byteRead = inStream.read(buffer)) != -1) 

                fs.write(buffer, 0, byteRead);

            }

            inStream.close();

        }

    } catch (Exception e) {

        System.out.println("复制单个文件操作出错");

        e.printStackTrace();

    }

}

------------------------------------------------------------------------------------------------------------  

// 重点到了 我们之前的操作 遍历文件获取的db 数据库  以及密码 现在就可以用 数据库和密码进行连接  

  密码正确  成功进入数据库 获取表信息   我下面获取的是好友的总人数  误差在 + -2 直接大部分这个

    这个需要自己观察表 进行查询

 /**     * 连接数据库     *     * @param dbFile     */   

  private void openWxDb(File dbFile) {

        Context context = MyApplication.getContextObject();

        SQLiteDatabase.loadLibs(context);

        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {          

          public void preKey(SQLiteDatabase database) {

            }           

             public void postKey(SQLiteDatabase database) {

             

                database.rawExecSQL("PRAGMA cipher_migrate;"); 

                //兼容2.0的数据库            }

        };        try {        

            //打开数据库连接         

           SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, mDbPassword, null, hook);    

                  //查询所有好友总数(verifyFlag!=0:公众号等类型,群里面非好友的类型为4,未知类型2)   

                    // Cursor c1 = db.rawQuery("select * from rcontact where verifyFlag = 0  and type != 4 and type != 2 and type !=33 limit 20, 9999", null);     

                  Cursor c1 = db.rawQuery("select * from rcontact where username not like 'gh_%' and verifyFlag<>24 and verifyFlag<>29 and verifyFlag<>56 and type<>33 and type<>70 and verifyFlag=0 and type<>4 and type<>0 and showHead<>43 and type<>65536",null);      

                      while (c1.moveToNext()) {

                String type = c1.getString(c1.getColumnIndex("type"));

                System.out.println(type+"参数");            

                    count++;

            }           // sqlt.setText("好友总数"+count);        

                System.out.println("总共参数"+count);        

                  //  Toast.makeText(getApplicationContext(),"好友总数"+count,Toast.LENGTH_SHORT).show();   

                           c1.close();

            db.close();

        } catch (Exception e) {

            LogUtil.e("读取数据库信息失败");//         

               e.printStackTrace();           

                //打开数据库连接       

                     // 根据imei和uin生成的md5码,获取数据库的密码(去前七位的小写字母)         

                   ///  initDbPassword("A100004AF6C883",  Uin);       

                        String MEID=readFileSdcard("/mnt/sdcard/meid.txt");

           String dMEID=MEID.replace("\r\n","");

            initDbPassword(dMEID.toUpperCase(),Uin);

            System.out.println(mDbPassword+"MEID---密码");      

                  count=0;

            SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, mDbPassword, null, hook);  

                      //查询所有联系人(verifyFlag!=0:公众号等类型,群里面非好友的类型为4,未知类型2)

                  // 获取好友总数           

                 

                   //   Cursor c1 = db.rawQuery("select * from rcontact where verifyFlag = 0  and type != 4 and type != 2 and type !=33 limit 20, 9999", null);        

                       Cursor c1 = db.rawQuery("select * from rcontact where username not like 'gh_%' and verifyFlag<>24 and verifyFlag<>29 and verifyFlag<>56 and type<>33 and type<>70 and verifyFlag=0 and type<>4 and type<>0 and showHead<>43 and type<>65536",null);    

                               while (c1.moveToNext()) {

                String type = c1.getString(c1.getColumnIndex("type"));

                System.out.println(type+"参数");             

                   count++;             

                   //Toast.makeText(getApplicationContext(),type,Toast.LENGTH_SHORT).show();      

                         }      

                        // sqlt.setText("好友总数"+count);        

                           // Toast.makeText(getApplicationContext(),"好友总数"+count,Toast.LENGTH_SHORT).show();  

                                     System.out.println("总共参数"+count);

            c1.close();

            db.close();

        }

    }

    

     //*//*读在/mnt/sdcard/目录下面的文件   

      public String readFileSdcard(String fileName){

        String res="";  

              try{

            FileInputStream fin = new FileInputStream(fileName);      

                  int length = fin.available();         

                     byte [] buffer = new byte[length];

            fin.read(buffer);

            res = EncodingUtils.getString(buffer, "UTF-8");

            fin.close();

        }        catch(Exception e){

            e.printStackTrace();

        }        return res;

    }
   

相关博客 我也是参考他完成的需求 http://m.blog.csdn.net/article/details?id=54024442 写的更详细 

破解成功 LOG会打印相关信息 可以进行查询  

也可以下载个 sqlcipher 数据库可视化工具 进行查看


排版 对付着看吧 我进行调整了 但复制过来还是 串行


http://blog.csdn.net/qq_35834055/article/details/67636801 我的博客

  https://github.com/1998lixin/WeChat-database    源码地址

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功