天天看点

iOS逆向抖音学习滤镜,你知道吗?

逆向不只可以让我娱乐别人的APP,我们也可以从别人的APP中学到一些东西,有时候我们会为了某种实现去逆向。由于前段时间公司项目需要写一个类似抖音的滤镜,不免就对抖音起了好奇心。最后效果如下:      
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
iOS逆向抖音学习滤镜,你知道吗?
IMG_0719.jpg工具依然使用MonkeyDev,然后是分析工具Hopper,log工具NSLogger步骤      

在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,小编欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程

  • 新建MonkeyApp项目
  • 从某助手下载不带壳的抖音
  • 使用Hopper找到filter的类分析
  • 编写hook代码
开始把抖音的可执行文件直接扔进Hopper里,直接搜索关键字Filter。      
屏幕快照 2018-01-24 下午5.49.39.png我们能看到HTSBeautifyFilter类,我们找到它的父类,双击initwith这个方法可以找到HTSGLFilter,可以发现这个应该是基类。我们就准备hook这个方法,这次我们需要拿到是滤镜的片元着色器的代码也就是ShaderString不太了解滤镜的也可以去google。上代码:CHDeclareClass(HTSGLFilter)CHOptimizedMethod(1, self,id,HTSGLFilter,initWithFragmentShaderFromString,NSString *,arg2){ LogMessage(@"filter", 1, arg2); return CHSuper(1, HTSGLFilter,initWithFragmentShaderFromString,arg2);}CHConstructor{ CHLoadLateClass(HTSGLFilter); CHHook(1,HTSGLFilter,initWithFragmentShaderFromString);}这样只要创建滤镜就会走我们hook的这个方法我们就能拿到ShaderString的代码。我们把项目跑起来发现会直接闪退。LLVM Profile Error: Failed to write file "default.profraw": Operation not permitted这个我google的很久没能找到解决的办法,不过这不能影响到我们,我们祭出神器NSLogger具体使用自行google。在注入动态库的时候,去设置ip 和 端口static __attribute__((constructor)) void entry(){ NSLog(@" !!!congratulations!!! ----------------insert dylib success----------------"); LoggerSetViewerHost(NULL, (__bridge CFStringRef)@"你的ip", (UInt32)50000);}到这里代码就完成了,运行完项目后,闪退,我们再次手动打开项目,这时候NSLogger会弹出来,我们进入抖音的加视频滤镜的地方选择滤镜。NSLogger就会显示      
屏幕快照 2018-01-24 下午6.00.34.png这样我们就可以把打印的ShaderString拷出来使用了。制作滤镜其实可以发现抖音的这个HTSGLFilter和GPUImage的滤镜是一样的,我们新建一个项目来测试我们拿到的ShaderString。新建项目导入GPUImage,新建一个类继承GPUImageFilter。代码:#import <GPUImage/GPUImage.h>@interface GpUImageScaleFilter : [email protected](nonatomic,assign) CGFloat scale;@end#import "GpUImageScaleFilter.h"NSString *const kGPUImageScaleFragmentShaderString = SHADER_STRING(precision highp float;varying highp vec2 textureCoordinate;uniform sampler2D inputImageTexture;uniform float scale; void main(){ vec2 newTextureCoordinate = vec2((scale - 1.0) *0.5 + textureCoordinate.x / scale ,(scale - 1.0) *0.5 + textureCoordinate.y /scale); vec4 textureColor = texture2D(inputImageTexture, newTextureCoordinate); vec4 shiftColor1 = texture2D(inputImageTexture, newTextureCoordinate+vec2(-0.05 * (scale - 1.0), - 0.05 *(scale - 1.0))); vec4 shiftColor2 = texture2D(inputImageTexture, newTextureCoordinate+vec2(-0.1 * (scale - 1.0), - 0.1 *(scale - 1.0))); vec3 blendFirstColor = vec3(textureColor.r , textureColor.g, shiftColor1.b); vec3 blend3DColor = vec3(shiftColor2.r, blendFirstColor.g, blendFirstColor.b); gl_FragColor = vec4(blend3DColor, textureColor.a);});@implementation GpUImageScaleFilter- (instancetype)init{ self = [super initWithFragmentShaderFromString:kGPUImageScaleFragmentShaderString]; if (self) { } return self;}- (void)setupFilterForSize:(CGSize)filterFrameSize{ runSynchronouslyOnVideoProcessingQueue(^{ [GPUImageContext setActiveShaderProgram:filterProgram]; [self setFloat:self.scale forUniformName:@"scale"]; });}@end这样我们滤镜就写完了,外面调用需要给scale赋值,类似这样 CIContext *content = [CIContext contextWithOptions:nil]; CGImageRef img = [content createCGImage:ciImage fromRect:[ciImage extent]]; GPUImagePicture *picture = [[GPUImagePicture alloc] initWithImage:[[UIImage alloc] initWithCGImage:img]]; CGImageRelease(img); GpUImageScaleFilter *scaleFilter = [[GpUImageScaleFilter alloc] init]; _scaleCount += 0.005; if (_scaleCount >= 1.2) { _scaleCount = 1.1; } scaleFilter.scale = _scaleCount; [scaleFilter useNextFrameForImageCapture]; [picture addTarget:scaleFilter]; [picture processImageWithCompletionHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ self.glkImageView.ciImage = [[CIImage alloc] initWithCGImage:[scaleFilter imageFromCurrentFramebuffer].CGImage]; }); }];因为模拟器实在是渲染不了,就不放效果动态图了。hook代码滤镜代码著侵权删