设备要求 已root的Android手机。 注:下面使用的两个微信安装包,com.tencent.mm.apk为旧版本6.5.16,weixin_new.apk为新版本6.7.3 背景 最近在弄一些关于微信的东西,测试过程中,本来打算强行停止后重新启动微信,结果手残点到卸载了。当我重新安装后出现了尴尬的情况,登录的时候,提示微信版本过低,需要安装最新版才能登录。 " u ~) p. ~7 b; }) Y
但是之前做的一些东西都是基于老版本的微信,所以不能安装新版本,必须想办法在老版本登录才行。 * {4 c( Z4 b' y e" I( R* B+ e
操作过程尝试1、替换版本号 最开始的想法是,既然要验证版本,那我就把旧版本的伪装一下,让它变成新版本的试试。 但是,因为没有时间去仔细分析微信是怎么验证的,于是就抱着侥幸心理,写了个xposed模块替换版本号, 一般情况下是通过以下代码获取版本号的: PackageInfo packageInfo = getPackageManager().getPackageInfo("com.tencent.mm",0);int versionCode = packageInfo.versionCode;String versionName = packageInfo.versionName;
/ B' _) c7 B5 r' O 所以去hook getPackageInfo方法,将其返回的PackageInfo中的versionCode和versionName替换成新版本的值就行, 但是,由下图可知PackageManager是一个抽象接口, 所以不能直接hook它的getPackageInfo方法,要先获取getPackageManager返回的对象的真实类型,先随便创建一个工程,通过以下代码获取真实的PackageManager类型, Log.v("test", getPackageManager().getClass().toString());4 P, d! O% l( j
. C' Q8 e( S3 ~. k6 c查看日志,可知真实类型为android.app.ApplicationPackageManager, 然后通过反编译最新版本的微信,获得versionCode和versionName, 最后的hook代码如下: [url=][/url]2 T: J. o2 w% d: o7 g8 n
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]
0 X& M( ]/ C1 K0 L4 v8 {( M( v
/ p" k4 W# i+ t 编译安装后重启,一边输入帐号密码,一边祈祷,结果还是提示版本过低,,
$ q. |" K7 \- i+ [( q& _尝试2、pm uninstall -k 命令 想着之前旧版本的都能正常使用,说明只要有登录数据,就可以使用旧版本的,所以想着先用新版本的把帐号登录,然后使用 pm uninstall -k 命令,卸载应用但保留数据,然后安装旧版本的。 先安装一个新版本的微信, 登录帐号, 3 B; X ^9 x; [4 o
使用pm uninstall -k com.tencent.mm卸载后安装旧版本的微信, 结果打开还是不行,还是提示版本过低,
! `7 x0 Q$ M2 t1 @2 J" h 于是怀疑卸载的时候数据被一起删了,根本就没有保留,再次执行pm uninstall -k com.tencent.mm,查看data目录,微信的目录已经不存在了。 尝试3、adb install -r 命令 同样先用新版本的把帐号登录,然后使用 adb install -r 命令强制安装,结果还是不行,不能安装比当前版本低的,,, , m5 C R8 ?! H/ Q1 L5 p& i/ S# f
尝试4、替换安装目录 既然用 pm uninstall -k 卸载时保留数据不行,那么就尝试手动替换。 首先安装低版本的微信,把安装目录复制一份,然后卸载。 再安装新版本的微信,并登录帐号。 用之前保存的旧版本安装目录替换新版本的安装目录,然后重启手机。 重启后提示登录错误,重新输入密码即可, 不知道为什么,这个手机在我写这篇博文的时候,关于微信的页面还是新版本的版本号,而我之前弄的另一个手机就是真实的旧版本号, 但是这个手机系统设置中微信的版本号已经变成旧版本的了,也不影响使用。 另一个手机的, ( U4 D3 R% d% J7 C [0 T
自动化程序[url=][/url]
# V' x. \' `, _package com.example.wxreversion;
! \! j( Y W. N1 f$ d4 \4 H* P! P$ k5 u2 v0 i3 E- X
import android.os.Handler;
& e5 U9 k( _% }/ ?import android.support.v7.app.AppCompatActivity;3 E& [, c0 \* N5 R
import android.os.Bundle;
. A& V* [$ g/ i3 ^! i9 iimport android.text.method.ScrollingMovementMethod;
- y$ Z9 x$ H" F- y* L9 i0 l! E6 {import android.util.Log;
8 J* S5 _1 `( s! U( A8 z, A# Nimport android.view.View;
1 n5 H. ~& i% H0 y9 c6 @4 Fimport android.widget.Button;, \; F( ?+ z# r1 |
import android.widget.TextView;/ w, }/ _* v( x1 Q
9 X9 ~0 E9 }2 G' `1 {3 w
import java.io.File;8 @/ |1 h$ x' w$ q; m* C5 |
/ v5 [' C3 p1 S* ?
public class MainActivity extends AppCompatActivity" I) d# g5 S% ^( n" d+ O
{
# |$ i3 B$ X% T# T. r Handler handler;
/ _5 p) v, F9 w, w2 ^ TextView textView;
! ]& ~& z' m+ s b7 s
) J' H8 ?* _5 G) B) t3 L% K2 P
7 ~$ z% b5 m J y- D/ A private void LogV(String s)& b" ~5 ~& t& ^2 G# [# g3 t. g( L, I
{
! F% ^8 ]1 g. P4 J, u- F; u Log.v("test", s); x. {6 o& P4 t U; |" _- ^3 ^$ F
}( ?& }! M4 l4 T9 q3 z; S* |( [4 J
" E$ h" m3 I* ]: i; q" i( U3 X3 I
private void textAppend(final String s)8 H8 Q) B/ e$ H o: W I
{
6 r% A; U2 x5 q7 t LogV("textAppend:" + s);& U( E6 f: _3 M, ]
handler.post(new Runnable()( q, F7 g5 u( D0 c: c) W8 M' {
{
Q" t. L# ^3 B1 P- Z5 i @Override5 ]: o D# q: ~* L# Q6 |. Z2 }
public void run()! Y8 s- \% N1 q1 Q- g% z1 ?, `
{4 f. e) l, o5 T, l
LogV("run:" + s);
W9 Q7 O; d+ h( W) |/ x) L
: h5 d, W. R) P, w- | textView.setText(textView.getText() + s);* k0 ]# z/ U; U" x V
}
5 J8 _* s# O; ~! i! M( J8 { });
$ R5 {+ k' j P3 D0 M3 W }
5 d% ^ s2 i; s, ^- Z8 I v0 D7 J
private String getPath()
' R' G+ u- B, s! ]- {6 o% u {
! ~3 ~9 F9 b" V String path = null;
8 c# _8 f; r1 J8 }" D7 ?6 { textAppend("-----------------------------\n");+ M: E3 j5 k& d1 ~ k
2 R7 E- a) j6 b6 R: t* {
) `: y; Z% m6 r* v; N if (!ShellUtils.checkRootPermission())& O1 A8 h: g v
{* I* S. s2 ~) K& ^% Z+ E* h
textAppend("获取root权限失败,请在设置中授予权限!\n");
4 _/ H; C) {( e$ M return path;$ M# N8 p0 w+ |! l, L5 p! [3 t4 y8 z
}$ C8 |: r1 z6 g. R
/ A* v$ M r Z. ]- K path = ShellUtils.execCommand("pm path com.tencent.mm", true).successMsg;
$ R$ V" w& d, m5 n' w* q* O if (path != null)
M5 P# Y% Q5 J0 ? {9 t R% d/ Z* V# ]5 q$ h' x
try" s3 C4 G4 }8 D7 s& t: v
{
7 M: l+ I; }$ R* s# |- N) Y, g$ | path = path.substring(path.indexOf('/'), path.lastIndexOf('/'));
% L/ _# p5 G; O$ X! N } catch (Throwable throwable)% m! I" e h. X' s( Z0 C) v
{$ H5 w0 W0 i. ~ y" w g) V, U+ X
path = null;
/ ]5 z8 R( e2 ? }) X3 ~$ Z- l# Z+ L( F
}. z4 d" H3 Y8 n( Z* |
) f7 x& L4 h/ n1 w( o/ y# x) d" d) w D
if (path == null)
4 c7 N$ L; \7 G7 W {8 T- Q) a3 }7 T
textAppend("未找到微信安装目录,请先安装!\n");7 z$ P, _. V/ H% ]# U& |
} else
+ G) D$ z1 C$ v, b" `* G {+ J/ Y3 C+ Y0 J0 L. r8 G1 ~& S* Z$ W# w
textAppend("找到安装目录:" + path + "\n");
, R: w0 i4 Q; J }# x3 A% y: s1 v& X# b& ?/ x
* E1 Q2 I E. p( F return path;
, S' o; `) M% p) A }/ ]$ p- u3 w! S- z& j f8 i: X
- T& }4 @3 d" y. a0 g
private boolean isEnpty(String string)
1 n2 P( p& {/ u! ^% o! O3 t {
8 W' @+ Z5 ~& j2 o/ u% J2 l( O if (string == null || string.length() == 0)" l2 n9 Z0 Q% k5 O4 f) ^
{4 X8 Y) G' I5 A8 d$ W
return true;$ J( V1 ?2 H- W" I- S
}: v# h, ~ @ W6 Q! L
return false;
% a; |7 \( P) j* Y5 v3 t3 N }- B/ Q, e" ^4 d& v
& {, {$ k( p9 ]
private void putResult(ShellUtils.CommandResult result)5 @; l6 Z T- Q/ O- o) m2 F$ ^
{5 X' x+ H# K" `0 U/ `6 A; h
textAppend("返回码:" + result.result + "\n");
* D4 n5 R: `" D8 Y. f) B4 C! m) u5 q
) ?/ P' k" a4 l8 H8 B if (!isEnpty(result.successMsg))
5 u+ S( T& I# Q9 e {
/ h4 `2 S( o: S textAppend(result.successMsg + "\n");4 u9 b3 I- H( B2 c. @! Y! E
} else if (!isEnpty(result.errorMsg))
* u& L1 S9 d4 @2 w$ k# p {
0 v- x, Y5 P: f8 F) t+ F5 \ textAppend("错误消息:" + result.errorMsg + "\n");
& Q1 Z7 N1 k: A }
) d* b; M5 w7 | }
. ]1 }8 F3 J C4 y. p4 z2 e/ A. b w1 t
@Override
3 {5 Y* E9 `! _4 R G' l protected void onCreate(Bundle savedInstanceState)" v9 F, [& X" o& I6 V; _
{
5 O" f- P! E% v8 p super.onCreate(savedInstanceState);. q4 v0 K# Y6 Q. w
setContentView(R.layout.activity_main);
% J0 _( _, r( \ s% I: L8 ^+ q handler = new Handler();
/ e# }3 }5 f9 e
2 n. ~4 f- ]( i textView = (TextView) findViewById(R.id.textView);5 h- U& W- v7 \3 J/ b" [3 J
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
$ Y) n3 F; K$ @
( \% D+ a3 w$ X4 ?: c* G ((Button) findViewById(R.id.button1)).setOnClickListener(new View.OnClickListener()
5 P% ]4 w6 @# a0 Y) r0 X {" V$ y6 D5 c0 I1 [
@Override' X& d. Z" ~/ d2 z
public void onClick(View v)' \0 O) f7 R; H, r' B, C+ K8 [
{1 _/ u4 U* H9 _5 Q/ K- `2 z
# D$ y1 f1 m8 D* T3 z$ q
new Thread()
; G% h. S! G3 R. ]9 _+ {: T {- @/ G8 A: ]. T3 R3 H. f3 \0 i! o
@Override
- D0 g8 } C* U V0 ]2 e4 S public void run()4 b1 J1 J! h7 u& W
{1 q6 x8 X% F( k4 o; k# ]
String path = getPath();
! i9 X6 {- Z; X if (path == null)
9 B6 y) M$ f, s+ y$ k {
) R, q& N' ]0 K' t0 v return;' s9 v' C! r& ?1 G1 m4 c
}
7 a) G3 Y$ G# t$ ?; L2 k textAppend("正在保存安装目录!\n");4 w/ e2 M5 t' r7 Y/ C: `' o, ~
ShellUtils.CommandResult result = ShellUtils.execCommand("cp -af " + path + " /data/local/tmp/com.tencent.mm", true);+ q" c. p" z7 ^0 L
putResult(result);* M {7 U2 K! }! F9 f5 \
if (!isEnpty(result.errorMsg))5 q* ^" F- e( r# I
{
8 t# @, \' X+ v: [) M return;. \ _' `$ f/ \( {8 R5 w
}
7 g0 L3 k# Q( w& ^( \3 k! W& _4 B2 i$ C% R J* E
textAppend("正在卸载微信!\n");
. `* b' K* B. b result = ShellUtils.execCommand("pm uninstall com.tencent.mm", true);//-k无用) h y2 A* d7 e
putResult(result);" D! U% M$ H' j, y w! U( l+ j
if (!isEnpty(result.errorMsg))- B1 P4 ^# v+ P8 l1 U" e8 _! P
{
9 R9 p0 i( `; @5 U# W return;- E4 I4 i! ]( J' I! f
}
6 J8 G- d( }" V- j( w
# _8 l. U; e' P7 S) x# _. J textAppend("请安装新版微信,并在登录成功后点击【覆盖安装文件并重启】按钮!\n");; g3 {. A$ D% r, k
}
$ J) M- R* i: x. N5 S( M: h }.start();# F8 f. r2 K3 ]" L, z
w; M+ V8 E2 y; y
}1 f9 [/ _7 I- z, O# R
});8 Y0 T' E! p! k# j" i4 t& j/ y
1 [2 }1 i w; J8 R5 y9 r
7 D' @: L* k; ]7 s6 X ((Button) findViewById(R.id.button2)).setOnClickListener(new View.OnClickListener()
6 S$ N- w" d1 G {
% m$ }. w7 a( i, N" L @Override. R4 x6 e! R, M2 m# n
public void onClick(View v)1 u: e+ e$ ^) v" d" \, ]- i7 A$ r
{
# a1 E. |; ~7 c! |
a+ R0 ?0 j$ ~. q2 I4 K new Thread()
$ }7 D8 d* ?* t+ i. q: t. D/ Q% o9 k7 A. l {2 A) ^- b. ?/ H/ y. j2 v
@Override) `4 c6 O8 F0 C1 j- M; Z; l4 V
public void run()( a% z( c' z7 i& V6 R6 m
{
1 ^$ Z: P1 _1 v8 { String path = getPath();
# E6 y7 b) I( L+ ?+ O# [7 t if (path == null)
. N+ c, t) g: X {7 Z! s1 k e( P6 f
return;/ b7 S5 d5 P" t5 Z! V
}
( b) W; {& G& B) n0 A0 y1 t2 L+ y0 T
6 |" a7 D3 e. q3 ^3 s" G' n textAppend("正在检查是否有备份的安装文件!\n");
; X+ @1 d0 L0 x2 v$ p: T if (!new File("/data/local/tmp/com.tencent.mm").exists())+ i; S7 L+ Z9 }) j. G5 P
{" \; v5 \/ t1 s
textAppend("不存在备份的安装文件,请先安装低版本微信后点击【覆盖安装文件并重启】按钮!\n");
5 p& ]+ L/ \: \ V$ ~ return;
/ I6 @0 k9 ?; `' J }
6 [7 r/ q. d4 A" f7 k6 L- }
: Y9 c, @4 I5 y' d textAppend("已有备份的安装文件,正在删除当前的安装目录!\n");
6 H1 T) d! T1 s+ e ShellUtils.CommandResult result = ShellUtils.execCommand("rm -rf " + path + "/*", true);1 x n2 }0 P' ^) _* S, M
putResult(result);
5 g: x. l0 R' X% g; A |, B if (!isEnpty(result.errorMsg))/ e1 x- E9 O% e, R- I/ a$ z
{
3 X/ a5 x( C, K% J: N$ D. L return;
$ h$ O) F# G/ o: \ M }8 K" ^; n+ x, |( Y" K1 [% H
( h) E6 {' T+ o& A6 ^4 P) v
0 ~1 z# [+ g5 {3 n6 l; @: O& `. O textAppend("正在覆盖安装目录!\n");1 e) Q6 D6 R2 M; a
result = ShellUtils.execCommand("cp -af /data/local/tmp/com.tencent.mm/* " + path, true);
& Y0 d1 P% d3 a8 l+ o+ {3 { ShellUtils.execCommand("rm -rf /data/local/tmp/com.tencent.mm", true);
: d2 ~% D- B4 c putResult(result);! Q) Y9 q: e' Y8 k; ~, p
if (!isEnpty(result.errorMsg))
6 t, f& o3 O. B {" S+ {9 o; |& i1 a
return;+ o. A; J8 Y q4 [5 [# Z
}2 f1 s2 o" K; \5 q/ G% N
: f) w8 e6 U" p9 A2 i textAppend("系统将在10秒后重启!\n");
0 G) D, R. n$ d3 L, H
$ v* F6 n7 p' p8 S' K% F
+ W8 z9 V1 D6 w6 p3 W try6 a( A/ K& k/ q- P; R
{
% b. m" M' c4 |1 M; t F sleep(10 * 1000);6 u9 v+ R1 w2 H
handler.post(new Runnable()* z* l. T; Y5 l
{
$ e, n% T% X* S% z @Override
) E$ `& I4 t/ s4 X public void run()
8 g) [2 C; c4 |8 {" w1 r% b2 T {* p9 ~ ?; @6 j0 f4 ~* z
ShellUtils.execCommand("reboot", true);: ^ R2 v0 O Y2 S* t
}
6 y4 G) s& w* ~7 h, E3 l });
/ U, z5 e* _' Z5 ^! e; V, k$ \2 F& K } catch (InterruptedException e)6 `! c7 X& h' q& \1 {
{
7 M) q' l3 t! b4 x" c! i8 \9 B e.printStackTrace();$ L" H: e3 K# t2 Q
}0 L% ?" s: m$ b- P
}
$ }2 a h" n3 Z+ \% z; U }.start();$ J8 b4 S! }; Q. \8 v, G
! \$ J( e3 Z! N6 n1 ^9 y }7 |8 t0 E9 K5 p' l" Y6 C9 @
});. @/ A4 H0 _3 W; l' C6 t o) ~
" x6 F6 k# N& F& i+ Q+ f; D textView.append("-----------------------------\n");
4 e0 m( E' Y5 s/ ?3 t4 d textView.append("该应用需要root权限!\n");
" v0 W( C& l" Q: B/ z9 o/ O/ R; w if (ShellUtils.checkRootPermission()). X/ G& E) t+ z
{; [( F3 N9 v0 {9 r, j0 s
textView.append("获取root权限成功!\n");" |" o" a$ [" E7 N8 q
} else* ` g4 [) l% J9 K# f
{
4 M9 o( z! ?6 A5 A% s* p/ T0 X textView.append("获取root权限失败,请在设置中授予权限!\n");4 g3 l- {$ g/ l9 @4 [" w: y' c+ r
}
0 q" ]. a4 a- N: J0 t4 }! U" @( Z9 ^. |7 k; J8 g
! ?5 L, |0 q" n% _" y
}
7 T' M) [8 Y q( H |}[url=][/url]& E1 ]( @4 Z: [ \$ J
/ ^" \- h7 t$ H4 H: J
- b6 U7 u: v5 b3 X4 ~运行如下: 先安装旧版本微信, 运行该程序,点击左边的【保存安装文件并卸载】按钮, 安装新版本微信并登录, 点击右边的【覆盖安装文件并重启】按钮, 重启后重新输密码登录即可。 9 e4 b1 x% U5 I- I; W) l
安装包在release目录中 1 g1 z ]- ~8 G( n1 ^! e; \, U
|