Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iTeaTime(技术清谈)【002期】【代号:刺客信条】 #3

Open
ChenYilong opened this issue Jul 16, 2019 · 0 comments
Open

iTeaTime(技术清谈)【002期】【代号:刺客信条】 #3

ChenYilong opened this issue Jul 16, 2019 · 0 comments
Assignees

Comments

@ChenYilong
Copy link
Member

ChenYilong commented Jul 16, 2019

iTeaTime(技术清谈)【002期】【代号:刺客信条】




下列题目可能出现以下虚拟的程序员,非实指:

  • 小地
  • 大风哥

1【问题】【果粉常识题】为什么iPhone有的后置摄像头上会有一个小孔,这可能是iPhone背面上唯一可能进水的部分,这个孔是干什么的【难度🌟】
【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】 iPhone 背部的小孔实际上是一个麦克风,它的作用是降噪。,故意放在远离嘴巴的位置,收集环境噪音,在通话时将环境噪音删掉。采用的是【双 Mic 降噪技术】

双脉降噪技术主要原理是,频率相同的声波会发生干涉,如果波频相同,振幅相反,则会互相抵消。

假设,手机底部的 Mic 收集到的声波是 Va,手机背部手机到的是 Vb;声波通过干涉相抵的简易公式是 Vm = (Va - Vb) * n; n 是差分电路的放大系数。

当手机处在一个噪音环境下,前后两个 Mic 收录的音波几乎相同,Vm1 = (Va1 - Vb1) * n; 若 Va1 - Vb1 无限趋近于 0,则 Vm1 无限趋近于 0

当我们利用 Mic 通话时,Vm2 = (Va2 - Vb2) * n, Va2 >> Vb2.

故而当我们及时身处在一个不算安静的环境,只要不遮挡手机背面的 Mic,我们听到的声音就是 Vm = Vm2 - Vm1, 理想情况下,Vm1 约等于 0; 但也有一些非理想的情况,例如,说话说未能对准 Mic,Va2 不够大,影响收音效果,声音变小。

AirPods 也是拥有两个 Mic,但 AirPods 采用的是上行降噪技术,筛选信噪,并做放大和降低。不过,耳机的降噪就是另外一个故事了。


2【问题】【计算机常识】小地做了一个微信机器人,每天给女神发今天天气真不错,你在干嘛?女神一直没回复。直到第99天,女神回复微信说,你这样做是没有用的。小地看到消息,高兴地说:我的机器人终于通过测试了!大风哥,拍着他的肩膀,语重心长地说:小地,你高兴得太早了。请回答:小地为什么高兴,大风哥为什么说他高兴得太早了。【难度🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】小地高兴在于他以为他的机器人通过了图灵测试,大风哥,说他高兴太早,是因为图灵测试的完整定义是指测试者与被测试者(一个人和一台机器)隔开的情况下,通过一些装置(如键盘)向被测试者随意提问。 进行多次测试后,如果有超过30%的测试者不能确定出被测试者是人还是机器,那么这台机器就通过了测试,并被认为具有人类智能。
这里30%的测试者无法成立。

3【问题】【iOS】小地是一名base北京的iOS程序员,他有一次要出差深圳,但想找几个能在深圳可以一起吃早餐的朋友。但他的iPhone没有越狱,于是他在北京打开Xcode修改了系统定位到深圳,成功在探探、微信、陌陌上分别找到了可以共度早餐的人。但由于连续看了三天的妇联首映,加之几夜没睡也没吃早餐,他早晨在酒店无法下床,他想故技重施,打开公司打卡软件修改位置打卡。但发现无法修改。只好请假下午去,扣了半天工资。请问:小地他怎么改的位置,为什么公司打卡软件改不了,是怎么做的?【难度🌟🌟🌟🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】使用gpx文件, Xcode 虚拟定位可修改模拟器以及真机的系统的定位。即使是从App Store下载的探探、微信、陌陌只要使用系统接口获取定位信息,就可以通过gpx模拟定位。

1 Xcode 中新建一个项目, 创建一个 .gpx 文件
2 高德获取经纬度,链接 https://lbs.amap.com/console/show/picker , iOS 端采用的定位坐标系是 WGS-84 , 而获得的定位一般是火星坐标 GCJ-02,把 获得的坐标转化为原始坐标:WGS-84或者直接用 Google 地图获取坐标,就不需要坐标系转换了。还有一个 gpx 文件生成网站:https://www.gpxgenerator.com/ 可以直接选择坐标,然后导出 gpx 文件。

参考链接:

标题&链接 手机端阅读
标题:高德获取经纬度API
链接:https://lbs.amap.com/console/show/picker
标题&链接 手机端阅读
标题:GPX Generator
链接:https://www.gpxgenerator.com/

3 修改代码 把 Location.gpx 文件里的代码 改为 要定位的经纬度
4 点击 Debug--->Simulate Location --> Location 然后运行

(Location 这个是新创建 gpx 的文件名)

举例 Location.gpx :

<?xml version="1.0"?>
<gpx version="1.1" creator="gpxgenerator.com">
   <wpt lat="21.021460306037525" lon="105.81782341003418">
       <ele>16.10</ele>
       <time>2019-04-11T17:59:18Z</time>
   </wpt>
</gpx>

钉钉也可以修改定位打卡,如果钉钉设置 Wi-Fi 打卡,公司只配置校验了 SSID,没有校验 DHCP 地址。把家里的 Wi-Fi 名称改得和公司打卡的 Wi-Fi 即可。

如果有一些打卡软件不能修改,那可能是因为未使用系统定位方法,或者未仅仅使用该方法作为定位依据。具体使用何种方法,可在另行讨论。但已知 iOS 定位方法有:GPS定位、基站蜂窝定位、Wi-Fi定位等多种定位方法,

精准度优先级可以为:

  • 首选是 GPS,
  • 然后是 GPRS(IP 和 routetrace ),蜂窝网络进行 routetrace 可以获取到第一个接入点
  • 然后是 Wi-Fi(IP 和 routetrace 和附近的 Wi-Fi 名),SSID 名的优先级比较低,主要是靠routetrace
  • 然后是附近的蓝牙设备

如果结合以上多种定位方法,这四个方案是同时的,组合起来命中率就很高了,取合理的定位结果交集进行反作弊也是一种思路。

但是在iOS13中对 Wi-Fi 定位权限进行了收紧,需要用户进行额外授权,相关的上下文可以参考下面的链接:

参考链接:

标题&链接 手机端阅读
标题:iOS13AdaptationTips-Network
链接:ChenYilong/iOS13AdaptationTips#24

另外,做灰产的,有一种外设,基于苹果 MFi 认证,配合配套软件直接提供修改后的坐标,Apple 的这一类产品,最初是给那些没有 GPS 模块的iPad、iPod做定位的功能弥补,让这些用户也能使用定位。但这类产品修改的也是系统定位,进而也可以间接做打卡用图。不过是需要实体的装置。这个就不在讨论范围了。

还有其他几种相关的情况,见下图:

越狱情况:
限制就更少,比如越狱后的钉钉小助手
未越狱情况,
hook系统的定位方法:
CLLocationManager相关,然后重新签名。
因为重签名后bundleID变了,
只要APP在打卡接口验证就可防止该漏洞。

4【问题】【iOS】小地是一名中级iOS开发,他最近学会了iOS黑魔法 - Method Swizzling ,他感觉黑魔法很方便,于是他大量使用了这个技巧,并默默分享给其他同事,想大家一起成长,一起用。大风哥是团队一名高级开发,听到后,告诫小地谨慎使用。如果你是大风哥,你会怎么去告诫他。【难度🌟🌟🌟🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】

优点:

区别于⼿动为每⼀个类编写埋点⽅法或者写⼀个基类来做统⼀的埋点,前两者在某些场景下⼯ 作量都不算⼩。可以做⼀个 UIViewController 的 Category,置换原⽣⽅法,在置换⽅法中将写⼊埋点代码,这样可以直接⼀键埋点完成。之后新增的 UIViewController 类也不需要再关⼼这些的埋点代码。

- (void)cyl_APOViewDidLoad {
Class class = [self class];
if (!([class isEqual:[UIViewController class]] || [class isEqual: [UINavigationController class]])) {
NSLog(@"统计该⻚⾯ %@", class);
}
}

置换 NSDictionary-setObject:forKey: 方法,用于防止 crash。 NSArray 同理。

- (void)cyl_safeSetObject:(id)object forKey:(id<NSCopying>)key {
if (object && key) {
[self safe_setObject:object forKey:key];
}
}

Swift 版本实现:

缺点:

总结:一时hook一时爽,debug火葬场。

原因:

以下为 Stack Overflow-What are the Dangers of Method Swizzling in Objective C?

参考链接:

标题&链接 手机端阅读
标题:What are the Dangers of Method Swizzling in Objective-C?
链接:https://stackoverflow.com/questions/5339276/what-are-the-dangers-of-method-swizzling-in-objective-c

中列举出的7个问题:

  • Method swizzling is not atomic
  • Changes behavior of un-owned code
  • Possible naming conflicts
  • Swizzling changes the method's arguments
  • The order of swizzles matters
  • Difficult to understand (looks recursive)
  • Difficult to debug

可见,其没有类似注解的东⻄,⽅法置换没有有效声明。如果滥⽤,反⽽会增加维护成本。若擅⾃使⽤未同步其他同学,会成为极⼤的项⽬隐患。尤其是⼀些封装的模块。

这里着重说明几个场景:

场景:(iTeaTime(技术清谈)@国家一级保护废物 提供答案)

如果多次hook了同一个类的同一个方法,
跟分类重名的表现是一样:表现为无法控制执行的先后顺序,与编译器build的顺序有关,但编译器顺序有不可控性。

比如下面的实现方法,可能出现方法覆盖的问题:

+ (void)load {
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewDidLoad); SEL swizzledSelector = @selector(XK_ViewDidLoad);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}

场景:(iTeaTime(技术清谈)@molon 提供)
Hook了具有继承关系的相同方法。

以下场景:

如果子类并没有重写父类的方法,拿父类的implement去swizzling本来就是错误的行为。

A<—继承---B<—继承---C
(B是A的子类,C又是B的子类)

A 里有 test 方法,但是 B 和 C 都没有重写。
通常如果要对 B 或者 C 的 test 进行hook的话,很多开发者都喜欢去给 B 或者 C add A.test 的 implemention。
那如果先hook的C,又hook的B,似乎就形成了C与A直接打交道的局面。但是以面向对象来说,C的原实现应该是B的当前实现才合理。
所以不应该hook当前类没有重写的方法,这种其实直接继承(或者加category方法)就可以做了,不需要hook,需要调用原实现直接[super test]即可。


原文标题 & 原文链接 手机端阅读
标题:《iTeaTime(技术清谈)【002期】【代号:刺客信条】》
链接:#3

Posted by 微博@iOS程序犭袁 & 公众号@iTeaTime技术清谈
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0


One more thing...

【非礼勿视】以下为彩蛋部分,建议28岁以上男性观看



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant