如何愉快地在Mac上刷朋友圈

2017-03-08 09:57:20来源:http://iosre.com/t/mac/7014作者:Sec-News人点击

事出有因

从前,有一款Mac软件,在2014.11.10发布了1.2版本,然后就没有然后了。 可能这期间,Mac微信开发组解散了又重建,解散了又重建。。。直到2016.08.16,它终于发布了2.0版本,这就是Mac微信。


不可否认,它越来越好用,但它应该可以更好用。例如,对于朋友圈重度用户,在Mac上使用微信聊天之余,浏览下朋友圈,想来也是极好的。


也是早在2.0版本,我发现了Mac微信中已经存在朋友圈相关网络接口代码,没想到半年多过去了,它还是这副死样。俗话说得好,自己动手,丰衣足食,干!!!



注:接下来内容涉及修改微信,相关代码纯属技术研究与爱好,请大家尊重腾讯公司对微信软件的知识产权,不要乱来。


厉兵秣马

要想工作做得好,前期基础要打好!


1. 与iOS类似,Mac上的hook也是以注入动态库的方式实现的。Xcode提供了动态库的模版,我们只需要简单的几行脚本就可以实现注入动态库。


1.png 1468x1042 189 KB


选择Build Phases->New Run Script Phase


#!/bin/bash
app_name="WeChat"
framework_name="MacWeChatTimeLinePlugin"
app_bundle_path="/Applications/${app_name}.app/Contents/MacOS"
app_executable_path="${app_bundle_path}/${app_name}"
app_executable_backup_path="${app_executable_path}_"
framework_path="${app_bundle_path}/${framework_name}.framework"
# 备份WeChat原始可执行文件
if [ ! -f "$app_executable_backup_path" ]
then
cp "$app_executable_path" "$app_executable_backup_path"
fi
cp -r "${BUILT_PRODUCTS_DIR}/${framework_name}.framework" ${app_bundle_path}
insert_dylib --all-yes "${framework_path}/${framework_name}" "$app_executable_backup_path" "$app_executable_path"

2.png 1584x758 73.8 KB


2.编辑Scheme,选择executable为WeChat.app


3.png 1802x1010 86.7 KB


3.编辑Podfile


platform :osx, '10.10'
target 'MacWeChatTimeLinePlugin' do
pod 'JRSwizzle', '~> 1.0'
end

4.宏定义


#define CBGetClass(classname) objc_getClass(#classname)
#define CBRegisterClass(superclassname, subclassname) { Class class = objc_allocateClassPair(CBGetClass(superclassname), #subclassname, 0);objc_registerClassPair(class); }
#define CBHookInstanceMethod(classname, ori_sel, new_sel) { NSError *error; [CBGetClass(classname) jr_swizzleMethod:ori_sel withMethod:new_sel error:&error]; if(error) NSLog(@"%@", error); }
#define CBHookClassMethod(classname, ori_sel, new_sel) { NSError *error; [CBGetClass(classname) jr_swizzleClassMethod:ori_sel withClassMethod:new_sel error:&error]; if(error) NSLog(@"%@", error); }
#define CBGetInstanceValue(obj, valuename) object_getIvar(obj, class_getInstanceVariable([obj class], #valuename))
#define CBSetInstanceValue(obj, valuename, value) object_setIvar(obj, class_getInstanceVariable([obj class], #valuename), value)

如此一来,基础工作就做好了,现在按下Command+R, 就能debug注入了插件的微信了。


知己知彼

在实现Mac端朋友圈前,先看看iOS端是怎么实现的。怎么看呢?


从UI入手,我们知道,iOS上实现下拉刷新,是通过检测tableView的scrollOffest来实现的,很容易就发现了调用链。


-[WCTimeLineViewController scrollViewDidEndDragging:willDecelerate:]
-[EGORefreshTableHeaderView egoRefreshScrollViewDidEndDragging:]
-[WCTimeLineViewController refreshHead]
-[WCFacade updateTimelineHead]
-[WCTimelineMgr updateDataHead:0]
-[WCTimelineDataProvider updateWithReferID:LatestID:]
-[WCTimelineDataProvider requestForSnsTimeLineRequest:minID:lastRequestTime:]

进入 -[WCTimelineDataProvider requestForSnsTimeLineRequest:minID:lastRequestTime:]


可以看到,朋友圈的刷新是通过创建SnsTimeLineRequest,然后监听请求响应进行下一步处理、显示。


那么,要实现在Mac上刷朋友圈的目的,最基础也是最重要的,就是要发送SnsTimeLineRequest,然后监听SnsTimeLineResponse。


那么,Mac端微信是怎么创建请求,然后监听响应的呢。


我在-[GetCDNDnsRequest init]下了个断点



之后在-[CdnComMgr GetCdnDnsInfo]中可以看到,大概发网络请求的流程是


GetCDNDnsRequest *request = [[GetCDNDnsRequest alloc] init];
request.baseRequest = [MMCGIRequestUtil InitBaseRequestWithScene:0x0];
MMCGIWrap *cgiWrap = [[MMCGIWrap alloc] init];
[cgiWrap setM_requestPb:request];
[cgiWrap setM_functionId:0x*];
[[[MMServiceCenter defaultCenter] getService:[MMCGIService class] RequestCGI: cgiWrap delegate:self];

剩下的就是在iOS中确认SnsTimeLineRequest的参数了。


一鼓作气

万事俱备,只欠东风!


@interface MMTimeLineMgr () <MMCGIDelegate, MMService>
@end
- (void)updateTimeLineHead {
SnsTimeLineRequest *request = [[CBGetClass(SnsTimeLineRequest) alloc] init];
request.baseRequest = [CBGetClass(MMCGIRequestUtil) InitBaseRequestWithScene:0];
request.clientLatestId = 0;
request.firstPageMd5 = @"";
request.lastRequestTime = 0;
request.maxId = 0;
request.minFilterId = 0;
MMCGIWrap *cgiWrap = [[CBGetClass(MMCGIWrap) alloc] init];
cgiWrap.m_requestPb = request;
cgiWrap.m_functionId = 211;
MMCGIService *cgiService = [[CBGetClass(MMServiceCenter) defaultCenter] getService:CBGetClass(MMCGIService)];
NSUInteger sessionId = [cgiService RequestCGI:cgiWrap delegate:self];
NSLog(@"%lu", (unsigned long)sessionId);
}
- (void)OnResponseCGI:(BOOL)arg1 sessionId:(unsigned int)arg2 cgiWrap:(id)arg3 {
NSLog(@"%d %d %@", arg1, arg2, arg3);
}
@end
Command + R !!!

满怀希望,按下两个键,结果。。。sessionId为0!!!


进入-[MMCGIService RequestCGI:delegate:] 可以看到,开始请求前需要从MMCGIConfig找到对应的MMCGIItem,很明显,找不到。没关系,照猫画虎,给它new一个就是了。



@implementation NSObject (MacWeChatTimeLinePlugin)
#pragma mark - MMCGIConfig
- (const struct MMCGIItem *)cb_findItemWithFuncInternal:(int)arg1 {
struct MMCGIItem *res = [self cb_findItemWithFuncInternal:arg1];
if (arg1 == 211) {
res = malloc(sizeof(struct MMCGIItem));
res->_field1 = 211;
res->_field2 = 0;
res->_field3 = 0;
res->_field4 = "mmsnstimeline";
res->_field5 = CBGetClass(SnsTimeLineResponse);
res->_field6 = 1;
res->_field7 = 2;
res->_field8 = 0;
}
return res;
}
@end
static void __attribute__((constructor)) initialize(void) {
NSLog(@"++++++++ MacWeChatTimeLinePlugin loaded ++++++++");
CBHookInstanceMethod(MMCGIConfig, @selector(findItemWithFuncInternal:), @selector(cb_findItemWithFuncInternal:));
}

打断点在 -[MMTimeLineMgr OnResponseCGI:sessionId:cgiWrap:]


6.png 820x1232 141 KB


成功了, 在SnsTimeLineResponse的mutableObjectListList可以看到有10条朋友圈数据,接下来就是将数据处理,显示出来的工作了。


效果图

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台