设备要求 已root的Android手机。 注:下面使用的两个微信安装包,com.tencent.mm.apk为旧版本6.5.16,weixin_new.apk为新版本6.7.3 背景 最近在弄一些关于微信的东西,测试过程中,本来打算强行停止后重新启动微信,结果手残点到卸载了。当我重新安装后出现了尴尬的情况,登录的时候,提示微信版本过低,需要安装最新版才能登录。
4 R: B# p' y! M# N2 l/ e4 o 但是之前做的一些东西都是基于老版本的微信,所以不能安装新版本,必须想办法在老版本登录才行。
6 _- @, R0 ^/ t) ?& R$ i操作过程尝试1、替换版本号 最开始的想法是,既然要验证版本,那我就把旧版本的伪装一下,让它变成新版本的试试。 但是,因为没有时间去仔细分析微信是怎么验证的,于是就抱着侥幸心理,写了个xposed模块替换版本号, 一般情况下是通过以下代码获取版本号的: PackageInfo packageInfo = getPackageManager().getPackageInfo("com.tencent.mm",0);int versionCode = packageInfo.versionCode;String versionName = packageInfo.versionName;5 E% \; B1 d+ Q; Q# `7 E, T
所以去hook getPackageInfo方法,将其返回的PackageInfo中的versionCode和versionName替换成新版本的值就行, 但是,由下图可知PackageManager是一个抽象接口, 所以不能直接hook它的getPackageInfo方法,要先获取getPackageManager返回的对象的真实类型,先随便创建一个工程,通过以下代码获取真实的PackageManager类型, Log.v("test", getPackageManager().getClass().toString());+ w" k5 W; N* _6 ]) F
" W# J; w" L S/ B: X0 k9 q* Z0 }: \查看日志,可知真实类型为android.app.ApplicationPackageManager, 然后通过反编译最新版本的微信,获得versionCode和versionName, 最后的hook代码如下: [url=][/url]
# D$ n2 g/ u$ k: }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]$ `. M! m& H" E- \3 l+ w
! O0 c) u. V5 o2 F0 {( H! z' s9 S" b
编译安装后重启,一边输入帐号密码,一边祈祷,结果还是提示版本过低,,
+ I! b% R, m+ g' _尝试2、pm uninstall -k 命令 想着之前旧版本的都能正常使用,说明只要有登录数据,就可以使用旧版本的,所以想着先用新版本的把帐号登录,然后使用 pm uninstall -k 命令,卸载应用但保留数据,然后安装旧版本的。 先安装一个新版本的微信, 登录帐号,
C8 M4 _' q& b! }! `3 y 使用pm uninstall -k com.tencent.mm卸载后安装旧版本的微信, 结果打开还是不行,还是提示版本过低, o9 c& M+ G0 M7 l2 o% ^( S
于是怀疑卸载的时候数据被一起删了,根本就没有保留,再次执行pm uninstall -k com.tencent.mm,查看data目录,微信的目录已经不存在了。 尝试3、adb install -r 命令 同样先用新版本的把帐号登录,然后使用 adb install -r 命令强制安装,结果还是不行,不能安装比当前版本低的,,,
" a$ l5 D: x& u3 Q& A尝试4、替换安装目录 既然用 pm uninstall -k 卸载时保留数据不行,那么就尝试手动替换。 首先安装低版本的微信,把安装目录复制一份,然后卸载。 再安装新版本的微信,并登录帐号。 用之前保存的旧版本安装目录替换新版本的安装目录,然后重启手机。 重启后提示登录错误,重新输入密码即可, 不知道为什么,这个手机在我写这篇博文的时候,关于微信的页面还是新版本的版本号,而我之前弄的另一个手机就是真实的旧版本号, 但是这个手机系统设置中微信的版本号已经变成旧版本的了,也不影响使用。 另一个手机的, 7 ^! M9 ~/ H* {: P0 {# ]/ _7 O9 [
自动化程序[url=][/url]
4 P- ~2 q0 x4 Spackage com.example.wxreversion;+ p2 m: O/ k$ `9 N" q% i0 M
+ G1 D; _* B6 K$ Jimport android.os.Handler;
9 Z! R$ n9 \' Ximport android.support.v7.app.AppCompatActivity;! C. ?: g! j2 b% N+ s, Y& p t' Z
import android.os.Bundle;& q8 t+ i8 y& [; Z
import android.text.method.ScrollingMovementMethod;" U- l3 J. K2 F
import android.util.Log;
8 i" C1 z$ E1 t: uimport android.view.View;
2 v3 c) s2 V V! ]6 Vimport android.widget.Button;: h; O ^0 G2 P0 f& ?2 T4 H" n
import android.widget.TextView;
; M+ T* K4 {4 }7 q+ @/ ? q) f# Y1 E( q
import java.io.File;2 k. m1 `- }# G# n0 W+ n1 m
( ]$ U" T1 s( k" f" Ppublic class MainActivity extends AppCompatActivity
& z+ V7 {2 x: e% K$ i1 o& f{& c/ p% ~4 N* z( Q( N
Handler handler;# B( V: L0 k( E% f) U
TextView textView;
( R1 b$ @0 X% S; _6 d6 l' ]* |! Z# r8 W. C. V
3 ~5 u( f6 _1 y4 I$ `3 A private void LogV(String s)" T( |# o/ d5 L
{
5 G) t2 a& z Q' { Log.v("test", s);. a3 [% [6 M8 @9 c& O
}, L. K- p" @6 Q# |8 Q# ?* ?
/ N7 |/ X/ j2 N4 W1 p
private void textAppend(final String s)8 {6 E3 I! v; [" Z" F
{
& w* b5 ~# V+ V LogV("textAppend:" + s);
" _& R2 v% V' w2 ~1 C% x: i handler.post(new Runnable(): w4 z$ y# s1 N% X M2 ^
{; o( O* l) V- e% G) p" u
@Override
. f4 f2 ^& [( A! Y$ m2 ] public void run(). c4 E! Q) u: Z
{
7 ]# d' p% w) q* e LogV("run:" + s);3 k b6 u J1 ]6 f' j% Q
6 m6 q" d: P' j4 B9 u& n& y textView.setText(textView.getText() + s);6 V3 J$ g6 `$ `' ^
}7 i0 k* N1 L& i
});, c) y% B) _( E# t, J5 r: Z
}; o: p, u+ m0 N& w( k7 s
% ?* L: ?( }, k2 b9 k private String getPath()9 q4 _. ~; ]2 `# {9 v) d
{! y, m+ a, S4 g3 V2 H+ Y
String path = null;6 l3 w- \2 U0 Z; |
textAppend("-----------------------------\n");
7 y% H2 D) L. C' G8 L6 _/ R! V! W% U0 I- N7 J6 |
; B' S& o9 ]* ^% \
if (!ShellUtils.checkRootPermission())
$ x4 A/ \* f2 ]/ q: ~( u. c. j) o {# s0 O' C& W- x; f; q1 L5 a
textAppend("获取root权限失败,请在设置中授予权限!\n");
: U7 Y! s: c$ S* X: }5 { return path;
. a$ T& {6 L. W7 H- t/ e3 X5 H1 E! S2 { }
) Y; e8 N4 b6 E6 ?5 D# @5 c+ H# ?7 U2 C) Q6 L5 x# P
path = ShellUtils.execCommand("pm path com.tencent.mm", true).successMsg;
1 C0 b+ ?* o% H% k% C& A( g, p if (path != null)# G/ Z# ?1 K( D
{
" s. G& d1 d" z$ _ try, I! I0 q6 ]% P2 q$ ]5 u2 e( X% C
{
/ K7 h; F- o7 K6 ~ path = path.substring(path.indexOf('/'), path.lastIndexOf('/'));
% }; _/ c& C0 E: u( y, p( _ } catch (Throwable throwable), s: n6 v) ~( R0 a
{
8 ~. V6 u$ G9 z* Q path = null;0 S# h( X3 y( R2 C) J% e
}
/ i7 L) A, B0 H- X5 o }4 {. V: V8 a2 }2 g7 y& S
+ K" c7 r% P. g' X4 U/ a; f6 I
if (path == null)
& j" ^$ O! y, `5 S {% x! w$ y+ i* N: n6 d! f- l
textAppend("未找到微信安装目录,请先安装!\n");8 S8 }' t- u5 ?, R0 f* U
} else: k2 ]% p% P9 a: B! {
{
9 c4 L* f+ Q, I- z textAppend("找到安装目录:" + path + "\n");& Q" B& g( e8 p: D% v
}
3 z2 K& @ W9 R a8 b' i8 j( p( Y( b X5 ^
return path;# @: K1 j/ S y) I
}
# s( y; c3 l9 U7 p" }+ m% a2 m* E9 @
$ [# G/ ?5 d* [$ u ~ T; _' x private boolean isEnpty(String string)
2 B% a# k z2 Y2 q! m {5 |2 J/ y7 g @! \+ r3 E. s! s# ~
if (string == null || string.length() == 0)
# t: L) c+ Q* l" f8 G {; m9 n* p' m2 b1 j
return true;
0 A$ H9 T$ ~- x5 \ }% V& k' r q2 |4 a4 F
return false;( S E4 Y; w& j) U, s i
}
6 S$ U' h1 f' g# l1 b& ?9 k0 T! _. x/ w5 A1 y
private void putResult(ShellUtils.CommandResult result)+ z1 `. k1 O1 S, f3 h. \ |, y
{: a. Z2 A& X* n d7 S+ g
textAppend("返回码:" + result.result + "\n");' R, h' @( k6 ~% t4 \" w
6 u$ O5 b- G( E" j& X% ]. Y if (!isEnpty(result.successMsg))
3 n( V% b. k4 v9 r* u, r/ f7 | {9 }/ |6 ` u6 W* w$ ^) C# Q
textAppend(result.successMsg + "\n");
! R8 }- A: |9 y; D } else if (!isEnpty(result.errorMsg))' v6 }) S+ L5 B0 I7 P1 A
{5 n6 U, [3 Q. H# E. V$ c8 X& Y% W
textAppend("错误消息:" + result.errorMsg + "\n");
. \; ^$ l- o6 o }
; w8 t" u6 H$ F+ ^; A }' l/ @# d( K* v7 x0 f
. V7 x; k# q9 N/ W @Override
- x% Q- e; w6 b0 Z7 o: z% G protected void onCreate(Bundle savedInstanceState)0 n/ ?# L2 A% `2 R g
{8 P' M( i! A+ ^
super.onCreate(savedInstanceState);
/ t0 v: r3 q4 {" X8 q6 p setContentView(R.layout.activity_main);6 y6 G/ k0 \7 h* @5 l
handler = new Handler();1 i3 @& X* I6 y* p& G
& @4 j1 u* r! Q z
textView = (TextView) findViewById(R.id.textView);* D% J7 f( C p0 m; Q
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
! v" o# a7 p- d2 U
. @ R# L0 H0 M5 z- B, j3 A# f ((Button) findViewById(R.id.button1)).setOnClickListener(new View.OnClickListener()
+ R% P; g3 s& n* l3 h {
& }; Q1 L( I+ ]# f) f" p @Override/ O, c* f9 Q ~. T( X. L a1 u
public void onClick(View v)) j C6 C/ V0 D- I
{: J5 ?7 Q! t7 d& x% _4 U
) z7 V* d8 \: M% M2 E: g new Thread()
4 M+ g' I$ r+ j) d, e* T+ B {
+ F4 I+ C1 m/ V* R @Override7 T5 L- \$ _- m6 r
public void run()8 e8 J8 A* A1 y- I) i$ P
{3 R0 v2 n3 a+ M" |+ w) f# F0 i0 H
String path = getPath();9 ^3 w3 f6 G) L
if (path == null)& I* A4 N1 H' p$ Z, @
{
3 k: d& y4 P g3 U9 m return;/ P: ^2 ~. r+ E9 \6 [
}
% V$ r+ D2 i6 p* w9 I( Z textAppend("正在保存安装目录!\n");( I* z% @" K3 T. f: Y3 l/ K
ShellUtils.CommandResult result = ShellUtils.execCommand("cp -af " + path + " /data/local/tmp/com.tencent.mm", true);
3 @% i, k; g: @! Q- B/ v putResult(result);
( f' U& u+ ?' y% I3 [ if (!isEnpty(result.errorMsg))
6 q6 ]1 z' o+ z& l: B O; Z {
0 R2 p2 w' g6 O8 A$ v return;& m3 U0 _' \" Q5 m: d6 d0 d: `
}
% m: k% A0 N7 c
e- A! w& D$ g" ^; X textAppend("正在卸载微信!\n");, n5 h# n0 C9 `4 o' M2 E9 R6 f" h7 S
result = ShellUtils.execCommand("pm uninstall com.tencent.mm", true);//-k无用
: Z1 c% o8 @- m# w4 r/ x* O putResult(result);! D1 ]7 v1 L+ X6 ~7 e S) r
if (!isEnpty(result.errorMsg))
) \1 q# }! q" ?# k {
, g+ m; p& `8 m0 ^ return;
; \% S, V5 E0 C/ f2 R9 b }
3 T0 w4 y6 s8 T7 C) @+ Q3 U: Y h: A- G2 ]
textAppend("请安装新版微信,并在登录成功后点击【覆盖安装文件并重启】按钮!\n");
0 ] o# ^8 L+ }6 A }
* o$ ~- T( ?$ x% A }.start();
9 J) A; Q. s1 _- m8 R+ U5 i# E, C% r; H* p* T d# M
}& I2 }! Y. U$ T
});1 w$ y2 [# Y8 D2 Z% |
$ R* M3 K5 @& ~- g3 B* E+ L
( j) B+ ]* D6 |$ S$ t/ p O
((Button) findViewById(R.id.button2)).setOnClickListener(new View.OnClickListener()! k0 N7 W9 O3 u) u
{. N- e7 X. l" R. R5 ]. j
@Override, [, ]3 _( h; b4 T5 r
public void onClick(View v)
/ v) ?+ a) D: u8 d0 T% V; \ {
6 L% f$ J% d+ |+ m, l5 p" q6 \+ E7 C1 _# z* |. s
new Thread()! P2 O2 x- @- c' S! i) O) P
{ j2 t; @& ^& A" ?! b1 z8 D
@Override" M+ R, m9 V2 B1 ~9 M
public void run(). @3 J% [+ I0 \; F0 K0 r
{
" V; ]2 T v) e; r% {* u String path = getPath();
! R5 a* b0 R0 r/ q; U( C, B2 p& S if (path == null)6 ]0 ]5 X3 n7 b# N7 w- A$ s+ l- V
{
; A) C5 s; J9 p. A0 u( h: k5 c return;( M0 b+ B |. e
} ~" ?: J. V) n$ m! a
4 u* P1 n- c/ G! [+ [, G5 T textAppend("正在检查是否有备份的安装文件!\n");
% s8 U# t9 q" Y: X if (!new File("/data/local/tmp/com.tencent.mm").exists())6 ?8 |* \0 _$ `3 f1 m- b8 J& K# {1 f0 P
{
. S5 t& q+ x8 c3 X9 l textAppend("不存在备份的安装文件,请先安装低版本微信后点击【覆盖安装文件并重启】按钮!\n");' r- [5 _! P/ t3 y4 i2 b
return;
9 E0 M" w6 Y5 j/ L }
" z- l k) S. A. Z3 K
$ f1 p; p0 ?8 }# T5 {) y textAppend("已有备份的安装文件,正在删除当前的安装目录!\n");
! |1 m- d# M1 x% f4 C# E ShellUtils.CommandResult result = ShellUtils.execCommand("rm -rf " + path + "/*", true);
9 I+ R7 |$ Z! L! ~ putResult(result);
0 x: `( L2 s% a if (!isEnpty(result.errorMsg))( }/ ~$ Y! K4 @) p, h+ J( B; g9 O
{
) S7 |6 \0 i, U6 j# X return;+ }: }4 o; g' |! s' M/ y9 O
}
8 n9 ^) X: I: E. p4 y/ E' C; k/ z7 }/ |
2 ?& u' x( S: M8 c' { textAppend("正在覆盖安装目录!\n");
+ [( M d! O! t) M result = ShellUtils.execCommand("cp -af /data/local/tmp/com.tencent.mm/* " + path, true);
? G8 {: @# ?3 Q( X5 T( X ShellUtils.execCommand("rm -rf /data/local/tmp/com.tencent.mm", true);
( G; P c( d9 _$ S putResult(result);5 r$ S: J6 T# }! a/ I( X
if (!isEnpty(result.errorMsg))
5 s( `* }9 E7 e: g$ f {
. B5 v. c. x9 P6 _ return;
# p( n5 _& Q& Y) ~3 p1 S }8 v& X7 A( _$ Y, R2 a3 V; U
& W9 A2 k7 [3 L- M$ X textAppend("系统将在10秒后重启!\n");3 J q4 J% K& V& {" |
/ S6 P, L" F) H& K, F, l2 D8 \- V
try
3 R( x; W" {0 C- T {
) E: d7 e! _& m5 Y; Q1 c6 c& W sleep(10 * 1000); F$ Y% N9 e2 T Y
handler.post(new Runnable()
* X# G3 W7 [! ?6 Y {( g' s C) r3 U8 y. d
@Override
* r0 n/ C6 k# u) x0 s; b public void run()( G- Q5 n' d; N5 T, V
{
, e6 D. _3 X" n7 t6 c% I ShellUtils.execCommand("reboot", true);" L y' p, E! X/ j' o* b7 l
}
$ r' S" r/ @ a) _+ H5 `) I });! s- e) g8 ^5 D% y3 J5 K
} catch (InterruptedException e)
: h# b9 A5 `! \* D; U9 Z0 a {* S9 ~2 K8 H, I4 I9 p$ Q; [
e.printStackTrace();: A/ X N, [3 H( _
}
3 o, }* |5 T* {( R+ D }
k0 b1 W! P. F }.start();2 c) {, c. c; H6 ^2 b, r& h
: n, Q- r7 d6 R6 H i1 D( ]# s
}- v Z# u5 d4 C
});8 u6 _+ `1 W# X! c
- [$ f& O- z& d) W textView.append("-----------------------------\n");
( E' f$ e7 y; J! K. u textView.append("该应用需要root权限!\n");
/ ~# B: T1 R9 U: E% d if (ShellUtils.checkRootPermission()): F q5 ~' W/ T! d; k
{
* @& Z% G. y, v& H textView.append("获取root权限成功!\n");4 r0 `, @# q4 s
} else
9 v) e( w8 t! u {9 P6 l8 {9 b; T8 V$ ^
textView.append("获取root权限失败,请在设置中授予权限!\n");
5 _5 ~# G0 A) `. G7 S; E! f; D; E# I }
% r5 @# Q$ D: X, U V
, X+ y9 g6 b. k& t7 F$ y) O) a' u/ G' h' p% N5 L
}
* E' l# s v- e I0 v}[url=][/url]
0 P3 X1 x5 I" r7 V& `
5 y# H0 S5 M; X5 o% t3 l5 S: d' F7 x v4 P0 t2 |! U
运行如下: 先安装旧版本微信, 运行该程序,点击左边的【保存安装文件并卸载】按钮, 安装新版本微信并登录, 点击右边的【覆盖安装文件并重启】按钮, 重启后重新输密码登录即可。
0 Y1 ^' v; W% V) u, ~安装包在release目录中 1 K% s; a& N+ F `& e4 ^/ ]
|