打开观察之后,发现这里面有个setAdapter的地方,对的!肯定数据就在这个Adapter里面,因为我们平时写list 渲染的时候数据都是通过adapter 渲染到list 上的,我们继续点进去看看这个adapter 是如何写的。
朋友圈Adapter深入
我们通过上述的方法已经找到了Adapter了,我们点击(this.qXz)这个字段发现他的类名是as,点击进去发现,果然没错。
public final class as extends BaseAdapter {
private Activity coM;
boolean cog = false;
private String country;
List list = new ArrayList();
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 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)) {
float f;
float f2;
float f3;
if (azc.vTb != null) {
f = azc.vTb.vTP;
f2 = azc.vTb.vTO;
} else {
f = 0.0f;
f2 = 0.0f;
}
if (f <= 0.0f || r5 <= 0.0f) {
if (azc.Id.startsWith(“Locall_path”)) {
str2 = an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.m(azc);
} else {
str2 = an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.d(azc);
}
Options akG = com.tencent.mm.sdk.platformtools.d.akG(str2);
…省略很多代码…
上面的字段local_path,博主感觉找到了那个点,开始hook这个method an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.m(azc);,surprise这个方法返回的值就是朋友圈图片的本地路径。打印下来是这样的路径
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
学习分享
在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题
七大模块学习资料:如NDK模块开发、Android框架体系架构…
只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!