设备要求 已root的Android手机。 注:下面使用的两个微信安装包,com.tencent.mm.apk为旧版本6.5.16,weixin_new.apk为新版本6.7.3 背景 最近在弄一些关于微信的东西,测试过程中,本来打算强行停止后重新启动微信,结果手残点到卸载了。当我重新安装后出现了尴尬的情况,登录的时候,提示微信版本过低,需要安装最新版才能登录。 3 T) [0 A* p1 D/ ]& Q
但是之前做的一些东西都是基于老版本的微信,所以不能安装新版本,必须想办法在老版本登录才行。
/ Z5 E7 Z- g+ a3 I/ h操作过程尝试1、替换版本号 最开始的想法是,既然要验证版本,那我就把旧版本的伪装一下,让它变成新版本的试试。 但是,因为没有时间去仔细分析微信是怎么验证的,于是就抱着侥幸心理,写了个xposed模块替换版本号, 一般情况下是通过以下代码获取版本号的: PackageInfo packageInfo = getPackageManager().getPackageInfo("com.tencent.mm",0);int versionCode = packageInfo.versionCode;String versionName = packageInfo.versionName;
2 J/ @3 d! I5 w. L 所以去hook getPackageInfo方法,将其返回的PackageInfo中的versionCode和versionName替换成新版本的值就行, 但是,由下图可知PackageManager是一个抽象接口, 所以不能直接hook它的getPackageInfo方法,要先获取getPackageManager返回的对象的真实类型,先随便创建一个工程,通过以下代码获取真实的PackageManager类型, Log.v("test", getPackageManager().getClass().toString());$ I T3 F I. w6 z
# C2 h& |' y+ j( P' O( R查看日志,可知真实类型为android.app.ApplicationPackageManager, 然后通过反编译最新版本的微信,获得versionCode和versionName, 最后的hook代码如下: [url=][/url]6 [$ \9 q& K: P( Q8 F
if (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]
8 \' q9 ~& V3 P$ n
6 g% ?$ `( \( @3 |1 f, |
/ O+ f9 }) K. [/ b, `' G2 ~ 编译安装后重启,一边输入帐号密码,一边祈祷,结果还是提示版本过低,,
5 _3 l0 q& Q1 k: j% m尝试2、pm uninstall -k 命令 想着之前旧版本的都能正常使用,说明只要有登录数据,就可以使用旧版本的,所以想着先用新版本的把帐号登录,然后使用 pm uninstall -k 命令,卸载应用但保留数据,然后安装旧版本的。 先安装一个新版本的微信, 登录帐号,
" m- |" r% e$ C9 M: o 使用pm uninstall -k com.tencent.mm卸载后安装旧版本的微信, 结果打开还是不行,还是提示版本过低, 6 p& X! `8 s H+ ]! [9 p' m" f1 ^- z
于是怀疑卸载的时候数据被一起删了,根本就没有保留,再次执行pm uninstall -k com.tencent.mm,查看data目录,微信的目录已经不存在了。 尝试3、adb install -r 命令 同样先用新版本的把帐号登录,然后使用 adb install -r 命令强制安装,结果还是不行,不能安装比当前版本低的,,,
q( l. v% S4 }' Y# ?# {; g" J" n尝试4、替换安装目录 既然用 pm uninstall -k 卸载时保留数据不行,那么就尝试手动替换。 首先安装低版本的微信,把安装目录复制一份,然后卸载。 再安装新版本的微信,并登录帐号。 用之前保存的旧版本安装目录替换新版本的安装目录,然后重启手机。 重启后提示登录错误,重新输入密码即可, 不知道为什么,这个手机在我写这篇博文的时候,关于微信的页面还是新版本的版本号,而我之前弄的另一个手机就是真实的旧版本号, 但是这个手机系统设置中微信的版本号已经变成旧版本的了,也不影响使用。 另一个手机的,
3 h1 u, e6 a Q' w3 \自动化程序[url=][/url]" l3 ?+ ]- C5 o4 { I( [6 Y
package com.example.wxreversion;* `5 o/ V' m! J' H
, Q7 E: X E l% d1 bimport android.os.Handler;
+ m, u: `( z' N$ b1 b, O5 ?import android.support.v7.app.AppCompatActivity;, ?' L* o2 t1 w; ]1 K
import android.os.Bundle;
1 L0 E$ r- l( ]: _( pimport android.text.method.ScrollingMovementMethod;
F& |# E. e/ h. U9 ?1 jimport android.util.Log;
) p9 H) d8 ~: m$ Cimport android.view.View;) _: W# h, [3 ]( j8 y' j
import android.widget.Button;3 Z% q, y9 s# ? u( t) {
import android.widget.TextView;
/ A( ]9 D7 V% N4 _! A3 f& P9 u0 `! R& O# T+ B, ]$ J. ~
import java.io.File;$ i0 C! [5 ]( r2 ]8 {3 C
( S5 X; O( D* \. h+ z; Lpublic class MainActivity extends AppCompatActivity2 i7 k/ Z/ J# i' P' Y. A% p
{0 ]. k/ B$ I2 x, V. b6 x
Handler handler;
& p& g7 W7 D" R TextView textView;$ N5 J$ A9 @; x, p; C
' I, |( r; H+ V3 B
7 d* G& B; e! @( t private void LogV(String s)8 N3 g: F& \* h {* H
{/ W8 M j7 i! [( {* j. d( L q; v
Log.v("test", s);
1 N! \9 P' |! t7 E }
, f! u- H: s, N2 U
2 o+ B0 C$ n8 ?; t5 s private void textAppend(final String s)
# z5 L6 e! g9 @8 e, W+ h {6 d. M. u) E+ R$ A# T: m
LogV("textAppend:" + s);( Q3 [5 B6 v4 F% h( c
handler.post(new Runnable()
+ ~6 ]! @( q" g0 x0 g {
- ~3 E8 T4 h8 X& A( k @Override! I Y+ B9 m1 S2 R; W1 \1 ~
public void run()' Y- P( _* u# k" K
{
D8 J7 T/ ~& ?; K6 r- u9 `8 [ LogV("run:" + s);8 A& X b. ?+ S: ^$ h" I: ]+ Q
9 F3 G- Z1 y! @# C* D" J
textView.setText(textView.getText() + s);2 {- f9 {! T2 }+ l$ Q: f# y/ ?
}
) L( w# N5 }" G$ ` });
& D7 O# ^6 e5 v6 {1 Y }: `+ W/ ]( W/ S6 b! Z7 `
+ r+ y) ?- Y2 w8 A private String getPath()
& O& s h$ G0 u% @) @, l) Q* c {- m; [, W f# g! U
String path = null;3 N' ?+ g" k- B
textAppend("-----------------------------\n");; v) _3 c; ?5 u( Q- O4 [1 b. F; q, Z$ T
) O; w9 m; h r0 }' j5 E% A& c5 O* M% E* _
if (!ShellUtils.checkRootPermission())- f4 L$ y. Y y- H; n: K
{& Z% `1 Z6 k+ T( }
textAppend("获取root权限失败,请在设置中授予权限!\n");! x6 O: @: B; \: Q C* m
return path;
. O: s( z8 n. G# t1 Y/ Y }
9 a- A6 k/ r: Y" |3 q( m
+ X4 ~4 M" ]; F+ g; x3 v path = ShellUtils.execCommand("pm path com.tencent.mm", true).successMsg;
4 C# ^% [5 m2 O& m$ K3 k if (path != null)
6 z; E6 H, m# u6 Z/ `# U4 w2 G1 x2 U {8 x$ H; n8 V( F! ?+ e. Q! `
try
0 e$ x G9 W' g) T( W" a {
& b2 q& _1 A+ c# g5 \$ e path = path.substring(path.indexOf('/'), path.lastIndexOf('/'));& D6 O4 A! m& N0 m
} catch (Throwable throwable)4 i2 x3 A N0 F# \) @
{# O0 x2 L2 l2 s6 M0 }: B# T
path = null;
! Z, V- O o0 r. w0 R% W" i1 C3 S/ X }
! V7 ]! S0 y9 y } B3 M( b* S' \. U5 \: r% r
7 x& f1 q1 C$ s4 v
if (path == null)+ L9 m! K8 g/ h& p1 c
{
7 D8 ?3 M! w4 O% Y textAppend("未找到微信安装目录,请先安装!\n");! d( V. S2 X4 e3 a! j/ ], k# T
} else" T" k- _! W. J Y: K
{0 ?0 Y5 F6 W; _% Z; k7 r) ]. N4 F* z
textAppend("找到安装目录:" + path + "\n");3 s a4 r% w, e2 H0 [$ ^6 n5 u0 g; a
}6 k2 x$ L' w: U' p# B
& h" v. n/ `0 `4 f L return path;
, j( ?: j/ b \! I- P }
: {% W# ~$ L+ Z% z. A/ D9 r) s/ p' h2 P+ v1 o
private boolean isEnpty(String string)
; S6 H' i( e, v/ {3 E/ \ {0 [/ q% }& ]9 M4 B3 I! y
if (string == null || string.length() == 0)& h' I# j# T1 a
{
7 m6 g* q6 Q! K7 h: T1 |5 F# @ return true;
/ [$ |9 O/ T* n! t }
+ x" H, u& f" L: O$ q: U, C/ c0 R& U return false;
3 c$ l a! ^+ y, l+ z2 o: S Y }
2 F( j- q3 C" N- O, c0 r. C4 Q$ F5 R5 ^& \
private void putResult(ShellUtils.CommandResult result)
4 Y+ y3 v f% S" y* j% d {( h+ X4 s5 }# }! ]& p
textAppend("返回码:" + result.result + "\n");
1 ~( L4 U, o1 O2 V( b. _7 Z1 A6 r; C @! y: P$ B5 j% _) _$ n
if (!isEnpty(result.successMsg))6 O7 P$ S3 b+ s' V% a
{3 D2 _+ t. B( S, ?8 j8 G
textAppend(result.successMsg + "\n");
; R) |% q* R. S } else if (!isEnpty(result.errorMsg))
5 S4 Y2 O: B3 q, S! ^5 i* A {
$ C: l D1 i& t# T, ? textAppend("错误消息:" + result.errorMsg + "\n");
" S# j& h) v7 g& p, f% J1 P }! A# V- F5 h7 S* t$ r0 k+ r% a
}
2 d5 w! u6 [: Z% n) B# t( e& ^) `. Z9 ?( V: E- B
@Override
7 ]* ]3 M6 a: ~' w protected void onCreate(Bundle savedInstanceState)/ S) k: N" l0 M/ P) y
{
$ I" }$ R9 ~3 n super.onCreate(savedInstanceState);
8 |) B+ A4 u9 Z' L7 g# A4 A$ S6 j# v) \ setContentView(R.layout.activity_main);4 p6 T- U' g) N9 @# p c
handler = new Handler();
6 f" c, H. a* q! s- D& g3 Q k" U7 O: ^
textView = (TextView) findViewById(R.id.textView);: ~4 Z3 n6 \8 b
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
. N6 ~- K1 e7 O: o8 q
$ \; G$ u" L6 T, u* b. y ((Button) findViewById(R.id.button1)).setOnClickListener(new View.OnClickListener()6 J) t) x, j* r9 N
{/ e) a8 q0 V4 u4 a
@Override. h [0 F$ ~$ n* i* z- J7 ^5 N
public void onClick(View v)# X$ T) p3 e. M* k
{0 T/ n. q' V0 H. |
: P& r) ~8 a, _9 H new Thread()) W0 f5 z" g" y K) ?! s4 E e
{
3 C- w& E) o! s5 i& [9 j% E! T @Override
$ Q, e0 C$ ^: B" y1 w) r g( w public void run()
. s+ s# i- H1 b) ?9 g {
9 e! {, ]- o+ t0 n/ m8 U String path = getPath();
v& b9 h/ F; S% ^( ` _3 [ if (path == null)1 R" ~) T$ l. I+ L
{$ N! R3 e2 C" N# I
return;' N5 [ g& L# o) j( K
} R' c# _( k9 `! l9 s
textAppend("正在保存安装目录!\n");0 L* n5 i. C! z, M4 h- V3 ^1 B3 p- ?
ShellUtils.CommandResult result = ShellUtils.execCommand("cp -af " + path + " /data/local/tmp/com.tencent.mm", true);5 S8 @9 g2 y' K/ @/ M
putResult(result);) B! d0 W- F) w4 C6 U# [
if (!isEnpty(result.errorMsg))
6 T: F, C- A( j) [" k( y* K5 x) ` j {- u7 O% E9 l i9 ?
return;
* o) d+ ? ?: T3 b3 Z* |; H' t- X" x }
- m& b3 u4 y( d" }3 L& y$ k* J5 @# x A! b( a
textAppend("正在卸载微信!\n");" ]( s# b+ N+ n* I& Q- D$ N1 k
result = ShellUtils.execCommand("pm uninstall com.tencent.mm", true);//-k无用0 V9 [3 E9 o/ O" ]9 O( F V, ^
putResult(result);
0 B& ]- I) h! V* B if (!isEnpty(result.errorMsg)). \) d2 z- k/ t! p
{
( l& ?7 X: H S1 n8 s4 O return;1 q" U$ a5 g7 G/ p4 w, y+ v
}! M1 J/ a6 M# y7 Y4 {: s
! n2 \* n. J. L4 q4 \
textAppend("请安装新版微信,并在登录成功后点击【覆盖安装文件并重启】按钮!\n");
; E l& }, N7 c; a8 g }4 \! ^$ \% D+ O* x9 q! n
}.start();, Q% J' D3 i1 g% J, @0 a3 @
4 M# o/ U* f0 b8 v
}
6 `1 a2 U( q" m) V. n3 s- r4 Z7 ~2 ] });- g& f; A- ]+ v4 R
4 O. L, }/ E- T; n) L. [5 ?
/ y. `$ d* k. w; n' ~0 C ((Button) findViewById(R.id.button2)).setOnClickListener(new View.OnClickListener()/ e. f$ i/ H" k# f
{
0 R0 L/ u9 R* ^% x# e$ \5 H. B2 A @Override1 x0 G" m9 m( f c2 s7 y
public void onClick(View v)" }9 O" m4 n2 t/ Z
{4 A5 A# z# o" Y- e( d
! Q% Y/ I5 _3 Q' Q+ e+ m2 F, C h new Thread()1 p; U5 B: j4 P' m u
{
8 c! S: ]2 a) z( u3 w4 } @Override
9 E3 E2 P4 f0 C5 R6 L public void run(), r q) P( j; P+ J5 u N' j
{
2 K5 e/ p8 I: I String path = getPath();
' O" _: O( }8 W/ C5 W if (path == null)/ _" S, d7 ^5 Z6 _. `
{* G$ ~! P! t8 |: ^/ N) ?; E2 R
return;
4 H. a: f1 C: |9 n }
$ @3 ?( x7 Q; i" `! U1 k7 }5 C9 n: y+ S; o2 \3 _% t# v
textAppend("正在检查是否有备份的安装文件!\n");
7 D G1 O- I. ]" e1 E if (!new File("/data/local/tmp/com.tencent.mm").exists())
- b& }8 g2 I$ u8 z( q. l" [' z" D3 N# P {0 l0 t$ E) s0 J% I2 B
textAppend("不存在备份的安装文件,请先安装低版本微信后点击【覆盖安装文件并重启】按钮!\n");2 D# V# a7 `, ]
return;
' ?4 i( M0 T/ N& ?* L( E }* U2 i( z1 ]! K* R! b
I9 o* O& P3 a: s textAppend("已有备份的安装文件,正在删除当前的安装目录!\n");
: @. o% H$ c b9 a& O ShellUtils.CommandResult result = ShellUtils.execCommand("rm -rf " + path + "/*", true);
/ U" n( t2 q! r* r putResult(result);2 N1 B4 x1 c- i: T5 _' d
if (!isEnpty(result.errorMsg))
% Z( L2 |# u% F( @ {
" j6 r5 \% Y) y) g return;# G/ `+ o) u- ?- U
}: i0 I6 X x. E: O" c" F3 G
. o' ?1 f$ Y! \! z- o; U) I
/ Y+ u" @, H9 ?2 |0 z textAppend("正在覆盖安装目录!\n");
J# N/ P" O* S+ e% p! X result = ShellUtils.execCommand("cp -af /data/local/tmp/com.tencent.mm/* " + path, true);8 V l6 s8 b" R3 }$ p
ShellUtils.execCommand("rm -rf /data/local/tmp/com.tencent.mm", true);! K! V S4 [ O8 X
putResult(result);# i$ ~$ W) e1 m5 M" R
if (!isEnpty(result.errorMsg))
) Y; P V" G* p {+ f: ~6 Q0 r* h# N/ n+ b
return;
4 d* p ^. D' ]3 c( w; q) L }) x1 Y! Y, c) p- T
E/ {8 g" @" U) L/ o" a
textAppend("系统将在10秒后重启!\n");, `( [2 L# U& Y _: e0 J8 G
- J. R, d1 s, |4 z2 Q
# y2 c# y2 c% `3 `; B try$ i) F. l( a5 F, _9 e
{
" z( L' P9 t" Z r) o$ b9 l# @8 b sleep(10 * 1000);% P N! E- b0 G: X! T2 ?2 R
handler.post(new Runnable()
' _' u3 i6 g. t/ B! G, v {; v: I1 q8 [- T1 _+ l
@Override
7 f3 Y8 t& R; u/ a1 |& W public void run()
) h; \$ X# C( Z$ x {
1 x ?5 u: ?* P! C ShellUtils.execCommand("reboot", true);
1 C/ z3 _$ i9 w& U9 p }
, ?% H9 C- z% k7 y: T# @: j0 i });
& I/ t) e6 {0 L) V8 V! T- b } catch (InterruptedException e)8 ~; j; ?5 J; ~" O# n) O) D, {
{
2 Z) ?& F. D- o _- l% o e.printStackTrace();
4 q# B& N8 u" L5 ~& u+ m7 o }
( C$ ~: b4 n' H; l. W$ A; p4 i( E3 s }
) G1 f/ x" Q. d# [' D) N! I0 p }.start();/ M# f# [$ A' r" e! w9 m
$ F3 G2 y1 k0 o3 z7 B# k' Q& M }$ k; c. E- }, o
});
0 { J! z0 J/ Y* V
* O# Z) l6 m1 g" @) a textView.append("-----------------------------\n");+ a6 w$ R. S- D$ \
textView.append("该应用需要root权限!\n");
8 }* N) ? F N if (ShellUtils.checkRootPermission())# D f F+ M8 X" Z
{* N; U+ D2 _- o* ~5 [5 @# B+ X0 X
textView.append("获取root权限成功!\n");
6 H# c+ |; u9 k } else
+ O4 u: Y3 m: o! F& ?1 X {
( t5 |' M2 A4 {* g" n3 _: n) Z M textView.append("获取root权限失败,请在设置中授予权限!\n");
% j/ @: V/ a' j& M) X/ e& \, l }
/ f% l) D4 m% B4 Z" P% F' Z" K. D7 ^3 ]+ V" H# J1 t5 X+ l
9 `2 @& ?8 E: u' X, ~
}
$ _6 Z5 V2 d% W* m! E" k8 W}[url=][/url]8 i/ g" A+ n9 Z
8 T2 f5 z" ^: g7 Q6 Q; `9 g
/ T- F! {9 E9 ~6 O5 o8 m( i- @& e' A运行如下: 先安装旧版本微信, 运行该程序,点击左边的【保存安装文件并卸载】按钮, 安装新版本微信并登录, 点击右边的【覆盖安装文件并重启】按钮, 重启后重新输密码登录即可。 ( |/ A' |4 ]7 L% D" s4 p5 H
安装包在release目录中 4 o5 A7 ^$ n, ~; D7 m- L
|