设备要求 已root的Android手机。 注:下面使用的两个微信安装包,com.tencent.mm.apk为旧版本6.5.16,weixin_new.apk为新版本6.7.3 背景 最近在弄一些关于微信的东西,测试过程中,本来打算强行停止后重新启动微信,结果手残点到卸载了。当我重新安装后出现了尴尬的情况,登录的时候,提示微信版本过低,需要安装最新版才能登录。
6 u* l( U. i" `! T, E 但是之前做的一些东西都是基于老版本的微信,所以不能安装新版本,必须想办法在老版本登录才行。
+ [+ Q) V# l( X, J( Q# ?操作过程尝试1、替换版本号 最开始的想法是,既然要验证版本,那我就把旧版本的伪装一下,让它变成新版本的试试。 但是,因为没有时间去仔细分析微信是怎么验证的,于是就抱着侥幸心理,写了个xposed模块替换版本号, 一般情况下是通过以下代码获取版本号的: PackageInfo packageInfo = getPackageManager().getPackageInfo("com.tencent.mm",0);int versionCode = packageInfo.versionCode;String versionName = packageInfo.versionName;
{" f, |' \: D 所以去hook getPackageInfo方法,将其返回的PackageInfo中的versionCode和versionName替换成新版本的值就行, 但是,由下图可知PackageManager是一个抽象接口, 所以不能直接hook它的getPackageInfo方法,要先获取getPackageManager返回的对象的真实类型,先随便创建一个工程,通过以下代码获取真实的PackageManager类型, Log.v("test", getPackageManager().getClass().toString());! Y! y& @, u3 @" ~
; u8 O; B j; ~+ ^+ H1 _查看日志,可知真实类型为android.app.ApplicationPackageManager, 然后通过反编译最新版本的微信,获得versionCode和versionName, 最后的hook代码如下: [url=][/url]
* n/ r9 X& t# {! K Q; ~9 kif (loadPackageParam.packageName.equals("com.tencent.mm")){ XposedHelpers.findAndHookMethod( "android.app.ApplicationPackageManager", loadPackageParam.classLoader, "getPackageInfo", String.class, int.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { if (param.args[0].equals("com.tencent.mm")) { PackageInfo packageInfo = (PackageInfo) param.getResult(); packageInfo.versionName = "6.7.3"; packageInfo.versionCode = 1360; } } });}[url=][/url]' u( v9 _/ Y! O/ H. e. ?
9 h4 B$ y% x+ `2 a4 C6 R
7 H* u) @5 i& C9 Q+ T- ~- ^' g
编译安装后重启,一边输入帐号密码,一边祈祷,结果还是提示版本过低,, 1 u- e2 M1 n2 O4 h
尝试2、pm uninstall -k 命令 想着之前旧版本的都能正常使用,说明只要有登录数据,就可以使用旧版本的,所以想着先用新版本的把帐号登录,然后使用 pm uninstall -k 命令,卸载应用但保留数据,然后安装旧版本的。 先安装一个新版本的微信, 登录帐号,
- l' z' m$ a: p B% d 使用pm uninstall -k com.tencent.mm卸载后安装旧版本的微信, 结果打开还是不行,还是提示版本过低, # Y& D( n, k& z! v/ T4 ^8 l
于是怀疑卸载的时候数据被一起删了,根本就没有保留,再次执行pm uninstall -k com.tencent.mm,查看data目录,微信的目录已经不存在了。 尝试3、adb install -r 命令 同样先用新版本的把帐号登录,然后使用 adb install -r 命令强制安装,结果还是不行,不能安装比当前版本低的,,,
/ r# d) r' ?4 }5 y$ e$ g尝试4、替换安装目录 既然用 pm uninstall -k 卸载时保留数据不行,那么就尝试手动替换。 首先安装低版本的微信,把安装目录复制一份,然后卸载。 再安装新版本的微信,并登录帐号。 用之前保存的旧版本安装目录替换新版本的安装目录,然后重启手机。 重启后提示登录错误,重新输入密码即可, 不知道为什么,这个手机在我写这篇博文的时候,关于微信的页面还是新版本的版本号,而我之前弄的另一个手机就是真实的旧版本号, 但是这个手机系统设置中微信的版本号已经变成旧版本的了,也不影响使用。 另一个手机的, ; Q( W, L0 X2 g6 S) f) i N# y
自动化程序[url=][/url]
( A! q* g# I- E2 o9 Tpackage com.example.wxreversion;8 x8 E( R \9 O8 a
0 o* R5 u2 t3 @- m0 e3 g! Y2 k
import android.os.Handler;
3 p% a1 Z# c9 n# n6 ?import android.support.v7.app.AppCompatActivity;7 U [, y8 s# p. R) S, y0 E' b
import android.os.Bundle;
0 A6 Q9 g/ U$ W* ~( \; K+ }+ eimport android.text.method.ScrollingMovementMethod;
$ k9 }0 n* b3 X9 F0 Q, T! }import android.util.Log;
: _7 |% i( j( pimport android.view.View;
: t9 p2 ]; V; fimport android.widget.Button;0 \) k( r4 o- v
import android.widget.TextView;
' p4 `* B* M" a4 e
& H: T! W% B1 l* J! Dimport java.io.File; s1 Q9 A4 T6 {8 a1 o1 i, M
$ ~+ h: x) w8 U! Rpublic class MainActivity extends AppCompatActivity* l4 R) [: M' S. J0 x e6 X
{6 s; a" h/ @9 [+ U& V! F# X \
Handler handler;
7 j- t& a0 J0 T& w' x# s O TextView textView;6 N: I% V) j2 w9 E/ H
N1 r) S$ G4 t5 @9 H+ G$ g s% o- O# f1 g7 W0 A
private void LogV(String s)
: ?. O7 {* N' J+ A {
3 g3 g4 _6 Y+ G/ f$ s Log.v("test", s);
8 C* W' l7 R' u; d5 b }$ v0 q5 i& }+ ~3 ~
( S8 V I/ }; h6 m! g9 B8 C private void textAppend(final String s)
" u e s1 l6 \ {
9 {- t+ d( f% x( H5 Q LogV("textAppend:" + s);
2 F/ L. o/ Z' [, b6 y handler.post(new Runnable()3 W2 |; Z- G9 L# Q
{6 Q' ^1 T+ B* ]' P
@Override
& P2 ]8 |9 ?# S8 q! d public void run()
$ c2 L; o7 u& R9 _4 f {. x9 b: `) D& u. s- A* H8 R" N
LogV("run:" + s);
9 t$ q3 k9 s4 R* \% }- o% {7 h3 N; S/ G4 v; `" S
textView.setText(textView.getText() + s);. e9 z; G) Q1 _4 A) }# ^
}
7 n0 G! J8 o6 l });
% Q+ D, A% Y* F5 F, j0 U }5 w& H' A- N1 d! i: z8 O
( ]3 n5 A! [+ S; B J( _- y$ m+ n private String getPath()6 y. ^7 K) B4 ~; I7 E3 e; D
{& Y! |" D* L, N2 j8 O& f* z
String path = null;
9 A& {6 I- b! c2 S9 i; p8 I! B textAppend("-----------------------------\n");) f2 M1 R+ \# R, l+ C$ F" H
" C) T3 I9 w2 Z- [) L; k2 i
; F% P$ [) ~, n+ ~$ s
if (!ShellUtils.checkRootPermission()), o, W; C- b/ Y
{
) M( h+ P% n/ V5 G: n9 c5 g textAppend("获取root权限失败,请在设置中授予权限!\n"); x2 S# |6 ]( g |, k1 j1 v
return path;
" y& E, {( z* `1 l' |# o }4 L" R" f' y( m! u
9 V# H, \& P" s
path = ShellUtils.execCommand("pm path com.tencent.mm", true).successMsg;9 |( J ^& p' n7 i& I8 @& y
if (path != null)+ V0 W2 ~4 {7 `# C% K& ^: n
{$ K& w# Q) t. |4 [- \2 y" S, f+ o
try8 C% {- N- ]$ Q* A5 I0 K* A. l
{
1 J; n% r4 M' m path = path.substring(path.indexOf('/'), path.lastIndexOf('/'));
% E) s* x9 c( v* T) | } catch (Throwable throwable)
( s6 c. ? t) N# l; i {
$ C4 q( X0 K! K# U path = null;1 e+ [8 b+ M; i. Y
}
; C3 }/ w9 \1 |) y2 t } q9 Y7 z9 K" @ k+ v
! L4 N5 s" z/ K% p if (path == null)
$ d8 v9 v& s1 L" c6 R0 f {# R/ q3 ?3 j1 J( c
textAppend("未找到微信安装目录,请先安装!\n");, w* v. U3 K% ~& `
} else T0 P8 c! r$ j8 F. S/ _# a
{( W6 \' _/ R: ~& J4 i
textAppend("找到安装目录:" + path + "\n");
% h, E1 s6 l( Z }
8 t$ m c+ A( V6 h/ h
/ e# n8 L! O: G3 V return path;& V. R/ y0 Y7 F# {: y. D0 J7 |4 a2 D
}
U- v- |1 k! r9 g% a# _6 B+ @& }. T# ~' N
private boolean isEnpty(String string)7 d, |* v$ M+ |
{$ N1 {# ]: @" Y$ z1 |( _) l, C
if (string == null || string.length() == 0)+ z7 K) D$ F$ \0 y( x1 u& a
{( Z! l5 T. A: ?& ^( x( n
return true;, ?! m+ t3 v* z( ~1 o1 a2 F
}; L* [/ h; F# i0 e( d7 X( G6 M B5 \( z
return false;" i4 k6 Q4 I; _3 w
}
" E/ D) D% W! q1 a3 A! K
e' W6 k/ v$ e( o+ X X8 A private void putResult(ShellUtils.CommandResult result)
- i8 n+ {6 n+ I5 P9 l8 \6 v {
: k1 O" h+ S5 o) z* S# M9 ^) D textAppend("返回码:" + result.result + "\n");6 d" b* x+ G3 G2 @1 p5 R1 o% p
) c3 ~" @# e* u% ~& N' j8 v+ H if (!isEnpty(result.successMsg))
; i0 O! U* n# }! g# J% l {+ p/ \& K' a& f
textAppend(result.successMsg + "\n");$ \! }9 W0 R% P" z$ m
} else if (!isEnpty(result.errorMsg))3 w& b" J( j- F1 {0 \
{( i* H: [3 z( Q! y
textAppend("错误消息:" + result.errorMsg + "\n");
8 k4 t* K0 N* [7 X }
4 o" ]: C ]# K' b% q4 J }
. v* f& n# o/ @& r( k
2 y3 s2 p) T- k' Q @Override
3 v1 q8 d. V& `) ` protected void onCreate(Bundle savedInstanceState)
8 F. f, Y% k: J' M4 ~9 K3 ? {
& ?1 K& E+ z0 {8 @+ I2 \$ k4 @7 F8 [ super.onCreate(savedInstanceState);
+ g. R: q1 S! H setContentView(R.layout.activity_main);4 Z7 h0 x, @# I0 A
handler = new Handler();# ]' z+ J3 X# i3 b; }! Q+ x) _
n+ M. j) |2 c1 `- o. x$ \
textView = (TextView) findViewById(R.id.textView);% ?) N( L! k# N1 M5 N6 H. s
textView.setMovementMethod(ScrollingMovementMethod.getInstance());0 g& b% e2 ?8 J
6 K- Z/ f4 s4 l6 z
((Button) findViewById(R.id.button1)).setOnClickListener(new View.OnClickListener()
/ n7 l% U( C2 N0 W# C {2 d$ P+ A4 ?) ~
@Override
5 _( `% y( D# c4 u' E9 | public void onClick(View v)
1 |# s( n: j4 P# Y; @ {
9 e0 D8 D0 A% L* j6 @
; L) |7 h$ q `& L* | P+ ^/ o new Thread()
2 s+ w' Z7 B9 t2 ] {
% L" ?3 Q: p: L" J' D2 p3 M' Q& N1 J @Override _/ G, w. c/ ]; b' O
public void run()# Q v. g5 V/ o' I$ w, N4 p
{
* S3 J0 q9 @( f# d String path = getPath();. T! P7 R$ O* q1 A
if (path == null)
) H3 y, w; d2 p# f x7 U" h {
4 {# D1 j9 x9 j( O8 P/ i9 E8 F return;
) y6 v3 i# }) _: O }
$ W0 P& P7 F9 ]' X E ]% G2 t0 ] textAppend("正在保存安装目录!\n");
9 |) l0 W6 m9 r$ l! N6 l ShellUtils.CommandResult result = ShellUtils.execCommand("cp -af " + path + " /data/local/tmp/com.tencent.mm", true);' f/ a) q" d- A* f' d7 }: Z& ?
putResult(result);" i& s( q; a6 d: p
if (!isEnpty(result.errorMsg))
( F8 r5 F+ K3 P0 U& e {, I/ i ]. ~: W6 c( ?
return; x0 z a' v' h4 a4 l
}
) g* R1 D6 G6 ?1 y9 h
" h0 i7 }0 G+ [5 k$ _- h textAppend("正在卸载微信!\n");
' {0 d5 @3 R8 g1 f result = ShellUtils.execCommand("pm uninstall com.tencent.mm", true);//-k无用
5 ^9 C/ y# M& B$ z putResult(result);& i+ w; q& O; N- b! c8 ~" w- V% q
if (!isEnpty(result.errorMsg))1 X9 z, }' P* I1 }0 @& b1 o' s! |
{$ |4 e p% l- z4 C
return; M! K3 ?4 i+ h6 ]9 J# L4 g( I
}1 M0 q2 s! |/ e" S9 D) r8 W! g
' P' \' d+ n6 Q# @2 P2 W; x! c textAppend("请安装新版微信,并在登录成功后点击【覆盖安装文件并重启】按钮!\n");1 C/ {0 R6 }2 Z. T2 a( {
}; w* C2 N% X' L+ x( p
}.start();- i3 g3 k) G% n' K# }+ [3 g
0 P. E" O& u, D& T2 ~
}
8 g$ |! z" G! i+ ~- s& E" H& j });6 @7 H, W- E! `
1 }5 C6 k9 E+ \6 ^
1 G' H7 n& T5 I+ t8 I2 j ((Button) findViewById(R.id.button2)).setOnClickListener(new View.OnClickListener()
! Z- P K2 ^1 K {
+ n, G7 ^- L1 e @Override* @% _) I; z- @& \$ q" P, z2 p! e
public void onClick(View v)0 C5 a6 _ } t; U% y9 u# }7 M) r- A$ f
{9 a9 E: e0 H# ^% D j; [* G' _4 Q
# |, b/ Z8 T% H$ X
new Thread()
" d/ [4 k" }* A) R$ t. A0 a {6 P/ `+ L9 ~( Y: E a# ]
@Override( _: z7 L7 x9 y3 i/ [
public void run()
1 n$ U* I: e$ a1 }, r" A. U {
; x1 e0 E; t- H$ N8 y String path = getPath();
: t0 q5 T& n. T' M. ?4 P4 \ if (path == null)
6 F( l: D: r! ~) P! Q" x {; X8 p7 z- v$ c; ^/ _
return;
) B/ [$ B6 t' B: r }1 M- R' J5 n$ i4 V1 a
/ e" P$ o @ v* T+ p. M. ^8 R textAppend("正在检查是否有备份的安装文件!\n");' K# O2 L% _: S
if (!new File("/data/local/tmp/com.tencent.mm").exists()) r% h# j/ k9 i
{
+ X" w8 i4 `3 F9 [0 l: z textAppend("不存在备份的安装文件,请先安装低版本微信后点击【覆盖安装文件并重启】按钮!\n");
6 ~! ~$ J: p3 O return;, q* \5 g5 P. G( B8 @' l! o9 o9 {
}/ e0 q6 [7 T6 h: ^0 Q7 u
# v2 ^% T7 j! H( L* C" n* z8 w3 J* a
textAppend("已有备份的安装文件,正在删除当前的安装目录!\n");' Z0 P/ [- T8 a0 ?' R( x
ShellUtils.CommandResult result = ShellUtils.execCommand("rm -rf " + path + "/*", true);& b# `' o' _% e T7 X
putResult(result);
, s4 @5 ~! }0 Q- r7 m" e if (!isEnpty(result.errorMsg))
- M9 X3 p9 b5 V6 Z. ?8 @ {
$ {- b% i( r: z! } [ return;
5 S k& d! b1 R& C }
) W$ x: s h$ _8 Q/ U; K o- p8 G* O: M: ~% X' e' J
; y; ]' r3 z& {/ v& W0 h7 s% Y D
textAppend("正在覆盖安装目录!\n");- Q( ~9 l! M" K( \
result = ShellUtils.execCommand("cp -af /data/local/tmp/com.tencent.mm/* " + path, true);
1 ^7 ^( c* g. R5 [+ y% k ShellUtils.execCommand("rm -rf /data/local/tmp/com.tencent.mm", true);8 h! h0 U$ |1 K$ D S H* H: Z
putResult(result);
3 Z* s" M$ D- n" i( v' o if (!isEnpty(result.errorMsg)); v3 h+ D3 T8 X* R" h
{
" f* g7 H* u) E; }& p6 X T( t1 h0 w return;
1 y/ C% L& `0 x( s8 \, \9 L! ^$ ? }
6 J/ L# {5 T! v: u/ [2 C8 { r( s. }5 [5 L' u7 u
textAppend("系统将在10秒后重启!\n");
7 w* J8 h5 N2 A1 Y& y t2 G+ [7 F% d' m( | g, v
/ I# v* t* F, ~) n' J try/ E( `* A f6 e! y% V L1 c. B
{
" ^3 {( u6 U0 E0 Q, D1 U sleep(10 * 1000);
3 g" R: E t: h: k! P4 y handler.post(new Runnable()
7 l6 k5 F! M f# X+ \ S/ u8 @$ E {/ ~7 Y7 ^% j8 l! G+ c1 e
@Override6 i8 U- K) h7 R7 S* T" R; J. F
public void run()' C( a! G) b+ t7 Z' h
{& L. U2 J% H! t7 s* d
ShellUtils.execCommand("reboot", true);
+ Q# c( O J/ S- Q( v% d% K/ b3 O# ~ }5 T0 v) f9 U( u2 E+ s% y' P( f7 h+ E
});8 P* Y! V5 k7 z' o2 e* @5 O
} catch (InterruptedException e)0 z! [% Z M5 ^$ X
{% D; [# G3 [ ^. t; @2 a
e.printStackTrace();
5 s$ ]. b4 g8 J }& F3 @' Y8 Y/ i0 [, d
}. f- |5 q. [1 G/ a1 U0 r V' v- S
}.start();' m3 K; [: a% b
3 P; {; x) `( L- J2 O* V }
) F9 V1 F* ^; P% P) k7 z9 F7 ` });2 w4 W, h b0 r' S
* O( d) W6 b+ V% V k2 ?
textView.append("-----------------------------\n");
) j$ E8 w& R5 y9 y% Z* ` textView.append("该应用需要root权限!\n");
5 x% G6 x2 P: `1 d if (ShellUtils.checkRootPermission())
5 K5 p* O! z# }$ A& Q: h; h {% B+ J6 A' y4 i9 |7 K
textView.append("获取root权限成功!\n");3 G9 g7 |+ j( P/ U7 @
} else
+ x [4 n0 G9 ~' J6 d {. g3 x9 u$ G! h$ }
textView.append("获取root权限失败,请在设置中授予权限!\n");. l$ B! Q" {/ t. `5 ~: l q- {
}" d" n8 f" |4 u: n# g! ]- S
0 A- N1 M! e" o. c5 { D( M- z
/ T1 b+ l6 U5 G8 Y0 c1 s }6 _: V( B" w K) h) P _
}[url=][/url]
# m% ]; b& \" d' E1 N
f P9 s0 u, F8 `1 b% Y4 O" }0 d2 B- D2 k# ]0 V0 h+ [
运行如下: 先安装旧版本微信, 运行该程序,点击左边的【保存安装文件并卸载】按钮, 安装新版本微信并登录, 点击右边的【覆盖安装文件并重启】按钮, 重启后重新输密码登录即可。 5 {! f/ n6 N, X& W }
安装包在release目录中 / Z( G; ^3 R5 q) k& G; A2 r
|