iOS逆向抖音学习滤镜

逆向不只可以让我娱乐别人的APP,我们也可以从别人的APP中学到一些东西,有时候我们会为了某种实现去逆向。由于前段时间公司项目需要写一个类似抖音的滤镜,不免就对抖音起了好奇心。最后效果如下:


IMG_0719.jpg

工具

依然使用MonkeyDev
然后是分析工具Hopper,
log工具NSLogger

步骤

  • 新建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(@"\n               🎉!!!congratulations!!!🎉\n👍----------------insert dylib success----------------👍");
    
    LoggerSetViewerHost(NULL, (__bridge CFStringRef)@"你的ip", (UInt32)50000);
}

到这里代码就完成了,运行完项目后,闪退,我们再次手动打开项目,这时候NSLogger会弹出来,我们进入抖音的加视频滤镜的地方选择滤镜。NSLogger就会显示


屏幕快照 2018-01-24 下午6.00.34.png

这样我们就可以把打印的ShaderString拷出来使用了。

制作滤镜

其实可以发现抖音的这个HTSGLFilterGPUImage的滤镜是一样的,我们新建一个项目来测试我们拿到的ShaderString。新建项目导入GPUImage,新建一个类继承GPUImageFilter。代码:

#import <GPUImage/GPUImage.h>

@interface GpUImageScaleFilter : GPUImageFilter

@property(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代码
滤镜代码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,020评论 25 707
  • “在快乐与美丽之间,我永远选择快乐,美不美绝非我之思虑。” “凡事量力,多年来她致力的并非美貌或夺目,一个人的时间...
    唐小山阅读 1,130评论 0 0
  • 构造函数的介绍 构造函数类似于OC中的初始化方法:init方法 默认情况下载创建一个类时,必然会调用一个构造函数 ...
    xiaoyouPrince阅读 215评论 0 0
  • 茵茵是在游泳池认识阿跃的。 那是初夏的晚上,游泳池人还不多。有个戴着条纹图案泳帽的男的在池中央游蝶泳,姿势生猛优美...
    琥琥妞阅读 224评论 3 2
  • 我有三次受难:流浪,爱情,生存。 我有三种幸福:诗歌,王位,太阳。
    楠土豆阅读 136评论 1 0