微信逆向之朋友圈,2021 最新 Android 大厂面试真题大全
String lnO = "";private String ngt = "";Map<Integer, Integer> qBc = new HashMap();Map<Integer, Integer> qBd = new HashMap();int qBe = 0;int qBf = 0;String qHI = "";private bd qKW = null;private az qQo;Map<Integer, Integer> qQp = new HashMap();private f qQq;boolean qQr = false;at qQs;private c qQt;int qQu = BaseClientBuilder.API_PRIORITY_OTHER;int qQv = 0;private long qQw = 0;private long qQx = 0;int qQy = 0;protected OnClickListener qQz = new OnClickListener() {public final void onClick(View view) {if (view.getTag() instanceof TimeLineObject) {TimeLineObject timeLineObject = (TimeLineObject) view.getTag();if (as.Yp(timeLineObject.Id)) {h.ptS.X(10231, "1");com.tencent.mm.av.a.agc();} else {h.ptS.X(10090, "1,0");if (!(com.tencent.mm.q.a.bN(as.this.coM) || com.tencent.mm.q.a.bL(as.this.coM))) {com.tencent.mm.av.e a = g.a(af.getAccPath(), timeLineObject, 8);a.fuR = as.this.userName;com.tencent.mm.av.a.b(a);}}as.this.notifyDataSetChanged();}........省略很多代码........
那我们接下来怎么找呢,Adapter 已经拿到了,难道还是一点点翻吗?当然不是了,想想我们日常写 listview 的 Adapter 时候,是不是在 getView 的时候进行给 view 赋值的操作,这时候微信也一样,我们同样打开 as 这个类的 structure 目录
从图中可以发 a 这个方法嫌疑很大,里面有各种 view
private void a(int i, QFadeImageView qFadeImageView, TextView textView, TextView textView2, TextView textView3, TextView textView4, int i2, d dVar, int i3) {n nVar = (n) getItem(i);TimeLineObject cmi = nVar.cmi();bys q = aj.q(nVar);Object obj = null;if (q != null && (((q.vUS & 2) == 2 && q.wnx != null) || ((q.vUS & 4) == 4 && q.vTG != null))) {obj = 1;}if (!(!this.cog || q == null || obj == null || this.userName == null || !this.userName.equals(nVar.field_userName))) {textView3.setBackgroundResource(com.tencent.mm.plugin.sns.i.e.personactivity_sharephoto_icon);textView3.setVisibility(0);}
........省略很多代码........
我们点进去可以看到,果然如同我们所想一样,第一行就暴露了, n nVar = (n) getItem(i); 可以发现这个 n 类就是每个 item 的数据源,而且往下看一行,这个类名也很有嫌疑 TimeLineObject,而且是通过 n 调用 cmi 方法返回的,那会不会是数据库里面的那个 BLOB 字段呢。容我们点进去看看
Map<String, TimeLineObject> qAb = new ConcurrentHashMap();........省略很多代码........
public final TimeLineObject cmi() {if (this.field_content == null) {return e.ahM();}TimeLineObject timeLineObject;if (this.qzT == null) {this.qzT = g.u(this.field_content) + g.u(this.field_attrBuf);}if (qAb.containsKey(this.qzT)) {timeLineObject = (TimeLineObject) qAb.get(this.qzT);if (timeLineObject != null) {return timeLineObject;}}try {timeLineObject = (TimeLineObject) new TimeLineObject().parseFrom(this.field_content);qAb.put(this.qzT, timeLineObject);return timeLineObject;} catch (Exception e) {ab.e("MicroMsg.SnsInfo", "error get snsinfo timeline!");return e.ahM();}}
这时候发现了不可思议的东西 field_content 和 field_attrBuf 这两个字段,这个不就是数据库里面定义的 content 和 attrbuf 字段吗。原来是通过这样的方式转化的。继续往下看,可以发现如果 ' qAb.get(this.qzT) ' 拿不到 TimeLineObject 的话,就会自己 new 一个然后存储到这个 Map 集合中,做缓存作用,那我们是不是可以通过这种方式呢拿到这个 TimeLineObject,当然是可以的。
解码朋友圈 BLOB 字段
通过上面我们已经知道了如何解析朋友圈数据库 content 字段了,通过 TimeLineObject 的 parseFrom 方法进行转化。但是当我们点到 TimeLineObject 这个类里面你会发现,卧槽,怎么这样。
public class TimeLineObject extends a {public String Id;public int dhE;public int eRm;public String hPC;public String jfn;public int ozl;public String qEy;public String qXr;public av qiN;public csw qiP;public String uzJ;public int vTa;public int wsA;public String wsB;public ccr wsC;public cqv wsD;public int wsE;public String wsu;public axc wsv;public du wsw;public ta wsx;public String wsy;public int wsz;
可以发现里面嵌套了很多的类。这是我时候我们怎么做呢。我也没有很好的办法,然后就通过一个类一个类的点开,然后打印它里面是 String 字段,这里应该来个表情捂脸,有好方法的同学们可以留言区交流,但是当我打印到了 wsu 这个字段的时候发现,可以拿得到我们发朋友圈时的标题了。瞬间感觉到了轻松。但是这只是一个很小的进步,我们要拿的可是朋友圈图片视频评论点赞所有内容啊。
获取朋友圈信息源具体内容
那么如何获取到图片视频等信息呢。那么我们还是要回到 adapter 这个类里面。在他的 a 方法中有个构造参数 QFadeImageView 看到 ImageView 感觉离获取图片地址不远了。那么我们继续观察这个方法。
private void a(int i, QFadeImageView qFadeImageView, TextView textView, TextView textView2, TextView textView3, TextView textView4, int i2, d dVar, int i3) {n nVar = (n) getItem(i);TimeLineObject cmi = nVar.cmi();bys q = aj.q(nVar);Object obj = null;if (q != null && (((q.vUS & 2) == 2 && q.wnx != null) || ((q.vUS & 4) == 4 && q.vTG != null))) {obj = 1;}........省略很多代码........if (cmi.wsx.vqt == 1) {qFadeImageView.setVisibility(0);af.cjr().a(cmi.wsx.vqu, (View) qFadeImageView, this.coM.hashCode(), com.tencent.mm.plugin.sns.model.g.a.IMG_SCENE_SNSSUSER, azVar);} else if (cmi.wsx.vqt == 2) {textView4.setText(bp.bb(cmi.wsx.Desc, ""));textView4.setVisibility(0);} else if (cmi.wsx.vqt == 21) {nVar.cmA();boolean z = true;if (this.cog) {z = true;} else if (m.a(nVar, q)) {z = false;}qFadeImageView.setVisibility(0);af.cjr().a(cmi.wsx.vqu, (View) qFadeImageView, this.coM.hashCode(), com.tencent.mm.plugin.sns.model.g.a.IMG_SCENE_SNSSUSER, azVar, z);}........省略很多代码........
从上面的代码中我们可以看得到,微信这边调用了这个方法把 af.cjr().a(xxxxx)把 Imageview 传入了进入,点击查看了其他的参数只有 cmi.wsx.vqu 这个参数有用。可以发现他调用了 TimeLineObject 里面 ta 这个类里面的集合 vqu 字段。
public final class ta extends a {public String Desc;public String Title;public String Url;public int vqt;public LinkedList<azc> vqu = new LinkedList();public int vqv;public String vqw;public ayd vqx;
先不管调用了 imageview 这个方法干了什么,我们先把这个集合里面的东西给打印出来。
azc.toString{id:13055580620160049319 Desc:黄昏 Title: Url:http://mmsns.qpic.cn/mmsns/kEgG3ynkRxponsiaCyzhl9Gniaz7GdWLujZdSMV4kmlME6fia07m577MQ3OU9kMKibjAIiaMc7MWHKF0/0 ckO:null qDg: vSY:http://mmsns.qpic.cn/mmsns/kEgG3ynkRxponsiaCyzhl9Gniaz7GdWLujZdSMV4kmlME6fia07m577MQ3OU9kMKibjAIiaMc7MWHKF0/150 vTc: vTf: vTh: vTi: vTj: vTm:f814a6351db8cd3ef118e14e6ff70b80 vTn:WSEN6qDsKwV8A02w3onOGQYfxnkibdqSOkmHhZGNB4DFJ9qdBeATTF8UiaDA1go3GLryav2ukPJK06SOFjchiaqJA vTp:14604729124651202068 vTq:WSEN6qDsKwV8A02w3onOGQYfxnkibdqSOkmHhZGNB4DFJ9qdBeATTF8UiaDA1go3GLwHGCkbxWxDWW5dsMhLsBUg vTs:14604729124651202068 vTt:}
不出我们所料,里面果然有我们需要的东西,而且把 Desc,url 都给了我们,通过我的测试发现图片的 url 并不能打开。但是视频链接的 url 是可以打开的。是不是很 happy。这时候我们已经拿到
了视频源和分享的链接源,但是如何拿到图片源呢。那我们继续查看源码,发现点击刚刚给上述调用了这个集合的方法里面并没有什么东西,都是一些赋值的操作。没有获取具体图片源信息的位置。
这时候我是这样操作的,因为这个获取到的 Url 虽然我们解析不了,但是我们可以点击查看 Url 的引用,看哪里有着对这个 Url 字段的引用,微信内部是如何解析的 当你点击开的时候会发现并没有什么用处,见下图
引用的地方太多了,根本不知道如何下手。这时候又会一头雾水不知道如何进行下一步。那么我们只能回到起点,再次寻找下一个 hook 点。
进入朋友圈详情二次 Hook
既然上一个页面我们拿不到图片的数据,那我们就深入进入朋友圈具体内容页面,然后进行二次 Hook,获取到朋友圈具体图片内容。我们还是以同样的方法进行,hook,打开此页面然后通过 dumpsys 获取当前的 activity,进入这个 activity 查看源码下手找到图片的具体位置。
通过代码查看到这是一个 com.tencent.mm.plugin.sns.ui.SnsGalleryUI,顾名思义,朋友圈相册页面。那么我们点进去看看具体写了些什么东西
public class SnsGalleryUI extends SnsBaseGalleryUI implements a {private int qKn = 0;private String userName = "";
public void onCreate(Bundle bundle) {super.onCreate(bundle);getWindow().addFlags(128);wS(this.mController.xyi.getResources().getColor(c.dark_actionbar_color));LV(this.mController.xyi.getResources().getColor(c.dark_actionbar_color));initView();}........省略很多代码........
并没有什么东西可看的。没有具体的内容,我们进入父类 SnsBaseGalleryUI 看看做了些什么进入看了一下,发现方法体也没有什么东西,但是一个字段引起了我的注意
public abstract class SnsBaseGalleryUI extends MMActivity implements a {private boolean jop = true;private LinearLayout qKf;r qKg;private LinearLayout qKh;s qKi;private boolean qKj = true;private TextView qKk = null;protected SnsInfoFlip qKl;protected Button qKm;........省略很多代码........
我们从上面的字段可以猜到哪一个是引起了我的注意,很明显那就是 SnsInfoFlip 这个类。继续点击去看看里面写了些什么内容。据我猜测这应该也是个 adapter,viewpager 的 adapter,通过 structure 目录可以发现里面有个 getView 的方法,但是反编译并没有完全把 smail 内容转换成 java 类型,看着比较费劲,那我们继续往下寻找,这时候你会有惊喜
可以看到这个函数里面参数是 azc 记忆力好的小伙伴应该还记得,前面所说的,azc 这个类里面包含着 url,这时候找到了用的地方了。把代码贴上大家可以看一下
private void a(azc azc, int i, String str) {String str2;long j = 0;if (this.qNm != null && (this.qNm instanceof MMGestureGallery)) {
评论