@ChiChou wrote:
Dash 不多介绍,
虽然他很多 bug 和安全漏洞,重度依赖这货查文档。适配 mac Mojave 新推的黑色模式的方式不敢恭维,如下图所示,会将网页(除图片外)整个反色处理。也没见 Safari 自作聪明把网页反色了啊。这种机械反色表面上一看还算和谐,其实在大量文字(特别还是非母语)的时候就觉得对比度不合理影响阅读。
简单分析了一下,Dash 实现 WebView 反色是在整个 View 上加了一层滤镜:
void __cdecl -[DHWebView setDarkModeFiltersIfNeeded](DHWebView *self, SEL a2) { void *v2; // rax void *v3; // rax void *v4; // rax const __CFString *v5; // [rsp+0h] [rbp-50h] void *v6; // [rsp+8h] [rbp-48h] id v7; // [rsp+10h] [rbp-40h] void *v8; // [rsp+18h] [rbp-38h] __int64 v9; // [rsp+20h] [rbp-30h] if ( (unsigned __int8)+[DHAnnoManager isDark](&OBJC_CLASS___DHAnnoManager, "isDark") && (unsigned __int8)+[DHSystemVersionChecker _isSierra](&OBJC_CLASS___DHSystemVersionChecker, "_isSierra") ) { v2 = objc_msgSend(self, "contentFilters"); if ( !objc_msgSend(v2, "count") ) { v7 = ((id (__cdecl *)(DHWebView_meta *, SEL))objc_msgSend)( (DHWebView_meta *)&OBJC_CLASS___DHWebView, "cubeFilter"); v5 = CFSTR("inputContrast"); v6 = objc_msgSend(&OBJC_CLASS___NSNumber, "numberWithDouble:", 0.95, CFSTR("inputContrast")); v3 = objc_msgSend(&OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v6, &v5, 1LL); v8 = objc_msgSend(&OBJC_CLASS___CIFilter, "filterWithName:withInputParameters:", CFSTR("CIColorControls"), v3); v4 = objc_msgSend(&OBJC_CLASS___NSArray, "arrayWithObjects:count:", &v7, 2LL); objc_msgSend(self, "setContentFilters:", v4); } } else if ( __stack_chk_guard == v9 ) { objc_msgSend(self, "setContentFilters:", 0LL); } }
这个反色非常暴力,可以看到 WebView 的审查元素功能也被反色了
这个很简单,直接在
setContentFilters
方法上加一个 hook 就好了。第二处处理是使用 WebKit 添加用户 css,在所有图片上加了一层 invert css 滤镜:
Image may be NSFW.
Clik here to view.此处代码质量真的不敢恭维(Dash 的 iOS 版本是开源的,可以去观摩一下什么叫烂代码,基本的循环什么都是不存在的,大段大段地 repeat yourself)
这里做自动化 patch 太麻烦了,最后我选择了在
setUserStyleSheetLocation
加载 css 之前打开这个文件,把含有invert()
的行过滤掉(其实这里需要一个 css parser,或者在 WebView 里用 javascript 匹配到这个规则然后移除掉,太懒了)代码抄袭了一部分 @Zhang 的某项目
// clang -shared -undefined dynamic_lookup -o /Applications/Dash.app/Contents/MacOS/libDash.dylib Dash.m // optool install -c load -p @executable_path/libDash.dylib -t /Applications/Dash.app/Contents/MacOS/Dash #import <Foundation/Foundation.h> #import <objc/runtime.h> static void pleasedontinvertwebview(/* we don't care about the args */) { NSLog(@"oops"); } typedef void (*OriginalSetUserCSSImp)(id self, SEL sel, NSURL *url); static OriginalSetUserCSSImp originalImp; static void pleasedontinvertimages(id self, SEL sel, NSURL *url) { NSLog(@"oops"); NSError *err = nil; NSString *content = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&err]; if (err) return; NSArray *lines = [content componentsSeparatedByString:@"\n"]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF contains[c] 'invert()')"]; NSArray *filtered = [lines filteredArrayUsingPredicate:predicate]; NSString *style = [filtered componentsJoinedByString:@"\n"]; [style writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil]; originalImp(self, sel, url); } __attribute__((constructor)) static void webview() { Method m = class_getInstanceMethod(NSClassFromString(@"DHWebView"), NSSelectorFromString(@"setContentFilters:")); if (m) method_setImplementation(m, (IMP)pleasedontinvertwebview); m = class_getInstanceMethod(NSClassFromString(@"WebPreferences"), NSSelectorFromString(@"setUserStyleSheetLocation:")); if (m) { originalImp = (OriginalSetUserCSSImp)method_getImplementation(m); method_setImplementation(m, (IMP)pleasedontinvertimages); } }
Posts: 2
Participants: 1