#import <UIKit/UIKit.h>#import <Foundation/Foundation.h>#import <AVFoundation/AVFoundation.h>#import <AVKit/AVKit.h>#import <StoreKit/StoreKit.h>#define LOGGING_ENABLED 1#if LOGGING_ENABLED#define ADBLog(fmt, ...) NSLog(@"[AB] " fmt, ##__VA_ARGS__)#else#define ADBLog(...)#endifstatic BOOL isAdClassName(NSString *cls) { if (!cls || cls.length == 0) return NO; static NSSet *adPrefixes = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ adPrefixes = [NSSet setWithArray:@[ @"ABU", @"CSJ", @"BU", @"GDT", @"KS", @"BaiduMob", @"MS", @"AWM", @"SMPopup", @"Oct", @"Octopus", @"WindMill", @"Wind", @"BeiZi", @"GM", @"QD", @"SM", @"AdView", @"AdController", @"AdWeb", @"Splash", @"Banner", @"Reward", @"Interstitial", @"DrawAd", @"NativeAd", @"FeedAd", @"BUNativeExpress", @"CSJNativeExpress", @"BUSplash", @"CSJSplash", @"ABUSplash", @"MSSplash", @"GMSplash", @"OctSplash", @"BeiZiSplash", @"WindSplash", @"KSSplash", @"BaiduMobAdSplash" ]]; }); for (NSString *prefix in adPrefixes) { if ([cls hasPrefix:prefix]) return YES; } static NSArray *adContains = nil; static dispatch_once_t onceToken2; dispatch_once(&onceToken2, ^{ adContains = @[ @"SplashAd", @"BannerAd", @"RewardAd", @"InterstitialAd", @"DrawAd", @"NativeAd", @"AdView", @"AdWindow", @"AdController", @"AdPlayer", @"SplashView", @"SplashCover", @"AdCardView", @"AdBottomView" ]; }); for (NSString *kw in adContains) { if ([cls containsString:kw]) return YES; } return NO;}static BOOL isAdURL(NSString *urlStr) { if (!urlStr || urlStr.length == 0) return NO; NSString *lower = [urlStr lowercaseString]; static NSArray *adDomains = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ adDomains = @[ @"pangolin", @"csj", @"bytedance", @"toutiao", @"gdt", @"qq.com/ad", @"tencentad", @"kuaishou", @"ksad", @"baidumob", @"bdstatic.com/ad", @"sigmob", @"inmobi", @"mintegral", @"admob", @"googleads", @"adview", @"unitad", @"octad", @"octopusad", @"beiziad", @"windmillad", @"ad.toutiao", @"pgy", @"ads.", @"/ad/", @"_ad.", @"splash_ad", @"banner_ad", @"reward_ad", @"track.", @"analytics.", @"collect.", @"yuanbao", @"元宝" ]; }); static NSSet *safeDomains = nil; static dispatch_once_t onceToken2; dispatch_once(&onceToken2, ^{ safeDomains = [NSSet setWithArray:@[ @".apple.com", @".icloud.com", @".mzstatic.com", @".cdn-apple.com", @"itunes.apple", @"api.", @"config.", @"login.", @"auth.", @"token.", @"upload.", @"download.", @"file." ]]; }); for (NSString *safe in safeDomains) { if ([lower containsString:safe]) return NO; } for (NSString *domain in adDomains) { if ([lower containsString:domain]) return YES; } return NO;}static BOOL isAdObject(id obj) { if (!obj) return NO; return isAdClassName(NSStringFromClass([obj class]));}// ================================================// Layer 1+2: 广告SDK展示拦截// 让SDK正常初始化和加载, 只拦截最终的展示方法// ================================================%group SDKShowGroup// --- ABU 聚合广告 (穿山甲GroMore) ---%hook ABUSplashAd- (_Bool)showInWindow:(id)arg1 { ADBLog(@"[Block] ABUSplashAd.showInWindow"); return NO;}- (_Bool)showInWindowWithBlock:(id)arg1 { ADBLog(@"[Block] ABUSplashAd.showInWindowWithBlock"); return NO;}%end%hook ABUBaseAd- (void)loadAdData { ADBLog(@"[Block] ABUBaseAd.loadAdData");}%end// --- CSJ 穿山甲 ---%hook CSJSplashAd- (void)showSplashViewInRootViewController:(id)arg1 { ADBLog(@"[Block] CSJSplashAd.showSplashViewInRootViewController");}%end// --- BU 字节跳动 ---%hook BUSplashAd- (void)splashAdWillShow:(id)arg1 { ADBLog(@"[Block] BUSplashAd.splashAdWillShow");}%end// --- GM 穿山甲融合 ---%hook GMSplashAd- (void)showSplashViewInRootViewController:(id)arg1 { ADBLog(@"[Block] GMSplashAd.showSplashViewInRootViewController");}- (void)showCardViewInRootViewController:(id)arg1 { ADBLog(@"[Block] GMSplashAd.showCardViewInRootViewController");}- (void)loadAdData { ADBLog(@"[Block] GMSplashAd.loadAdData");}%end// --- MS 美数 ---%hook MSSplashAd- (void)showSplashAd { ADBLog(@"[Block] MSSplashAd.showSplashAd");}- (void)showSplashAdInWindow:(id)arg1 { ADBLog(@"[Block] MSSplashAd.showSplashAdInWindow");}- (void)loadAndShowSplashAd:(id)arg1 { ADBLog(@"[Block] MSSplashAd.loadAndShowSplashAd");}- (void)loadAndShowSplashAdWithPid:(id)arg1 adParam:(id)arg2 inWindow:(id)arg3 { ADBLog(@"[Block] MSSplashAd.loadAndShowSplashAdWithPid");}%end// --- Oct 章鱼 ---%hook OctAdSplash- (void)showAdsInWindow:(id)arg1 { ADBLog(@"[Block] OctAdSplash.showAdsInWindow");}- (void)showAdsInViewController:(id)arg1 { ADBLog(@"[Block] OctAdSplash.showAdsInViewController");}- (void)showUniAdsInViewController:(id)arg1 bottomView:(id)arg2 { ADBLog(@"[Block] OctAdSplash.showUniAdsInViewController");}%end// --- BeiZi 贝兹 ---%hook BeiZiUnifiedSplash- (void)BeiZi_showSplashWithAdView:(id)arg1 { ADBLog(@"[Block] BeiZiUnifiedSplash.BeiZi_showSplashWithAdView");}- (void)BeiZi_loadUnifiedSplash { ADBLog(@"[Block] BeiZiUnifiedSplash.BeiZi_loadUnifiedSplash");}%end// --- WindMill 风车 ---%hook WindMillSplashAd- (void)showAdInWindow:(id)arg1 { ADBLog(@"[Block] WindMillSplashAd.showAdInWindow");}- (void)showAdInWindow:(id)arg1 withBottomView:(id)arg2 { ADBLog(@"[Block] WindMillSplashAd.showAdInWindow:withBottomView");}- (void)loadAdAndShow { ADBLog(@"[Block] WindMillSplashAd.loadAdAndShow");}- (void)loadAdAndShowWithBottomView:(id)arg1 { ADBLog(@"[Block] WindMillSplashAd.loadAdAndShowWithBottomView");}%end// --- QDSplashView %hook QDSplashView- (instancetype)initWithFrame:(CGRect)frame { ADBLog(@"[Block] QDSplashView.initWithFrame → nil"); return nil;}%end%end// ================================================// Layer 3: 播放控制 // Hook AVPlayer/AVQueuePlayer/AVAudioPlayer 的 rate// 条件判断: 只在广告上下文中返回0// ================================================%group PlayerGroup%hook AVPlayer- (void)setRate:(float)rate { @try { if (rate > 0 && isAdObject(self)) { ADBLog(@"[Block] AVPlayer.setRate ad"); return; } AVPlayerItem *item = self.currentItem; if (item && [item.asset isKindOfClass:[AVURLAsset class]]) { NSURL *url = ((AVURLAsset *)item.asset).URL; if (url && isAdURL(url.absoluteString)) { ADBLog(@"[Block] AVPlayer.setRate ad URL"); return; } } } @catch (NSException *e) {} %orig;}- (float)rate { @try { if (isAdObject(self)) return 0; AVPlayerItem *item = self.currentItem; if (item && [item.asset isKindOfClass:[AVURLAsset class]]) { NSURL *url = ((AVURLAsset *)item.asset).URL; if (url && isAdURL(url.absoluteString)) return 0; } } @catch (NSException *e) {} return %orig;}- (void)play { @try { if (isAdObject(self)) { ADBLog(@"[Block] AVPlayer.play ad"); return; } AVPlayerItem *item = self.currentItem; if (item && [item.asset isKindOfClass:[AVURLAsset class]]) { NSURL *url = ((AVURLAsset *)item.asset).URL; if (url && isAdURL(url.absoluteString)) { ADBLog(@"[Block] AVPlayer.play ad URL"); return; } } } @catch (NSException *e) {} %orig;}%end%hook AVQueuePlayer- (void)setRate:(float)rate { @try { if (rate > 0 && isAdObject(self)) { ADBLog(@"[Block] AVQueuePlayer.setRate ad"); return; } } @catch (NSException *e) {} %orig;}- (float)rate { @try { if (isAdObject(self)) return 0; } @catch (NSException *e) {} return %orig;}%end%hook AVPlayerViewController- (void)setRate:(float)rate { @try { if (rate > 0) { AVPlayer *player = self.player; if (player && isAdObject(player)) { ADBLog(@"[Block] AVPlayerVC.setRate ad"); return; } } } @catch (NSException *e) {} %orig;}- (float)rate { @try { AVPlayer *player = self.player; if (player && isAdObject(player)) return 0; } @catch (NSException *e) {} return %orig;}%end%hook AVAudioPlayer- (void)setRate:(float)rate { @try { if (rate > 0 && isAdObject(self)) { ADBLog(@"[Block] AVAudioPlayer.setRate ad"); return; } } @catch (NSException *e) {} %orig;}- (float)rate { @try { if (isAdObject(self)) return 0; } @catch (NSException *e) {} return %orig;}%end%end// ================================================// Layer 4: 视图清理引擎 (运行时递归扫描)// ================================================static void forceHideView(UIView *view) { @try { view.hidden = YES; view.alpha = 0; view.userInteractionEnabled = NO; for (UIView *sub in view.subviews) { forceHideView(sub); } } @catch (NSException *e) {}}static void forceRemoveFromSuperview(UIView *view) { @try { for (UIView *sub in [view.subviews copy]) { if (isAdObject(sub)) { ADBLog(@"[Clean] remove: %@", NSStringFromClass([sub class])); [sub removeFromSuperview]; } else { forceRemoveFromSuperview(sub); } } } @catch (NSException *e) {}}static void fullCleanup(void) { @autoreleasepool { NSArray *windows = [UIApplication sharedApplication].windows; for (UIWindow *w in windows) { if (isAdObject(w)) { ADBLog(@"[Clean] hide window: %@", NSStringFromClass([w class])); forceHideView(w); continue; } for (UIView *sub in [w.subviews copy]) { if (isAdObject(sub)) { ADBLog(@"[Clean] remove view: %@", NSStringFromClass([sub class])); [sub removeFromSuperview]; } else { forceRemoveFromSuperview(sub); } } } }}// ================================================// Layer 5: NSURL 过滤// ================================================%group URLGroup%hook NSURL+ (instancetype)URLWithString:(NSString *)URLString { if (!URLString || !isAdURL(URLString)) { return %orig; } ADBLog(@"[Block] NSURL ad: %@", URLString); return nil;}%end%end// ================================================// UILabel 文案过滤 // ================================================%group LabelGroup%hook UILabel- (void)setText:(NSString *)text { if (text && [text containsString:@"元宝"]) { ADBLog(@"[Block] UILabel ad text: %@", text); return; } %orig;}%end%end// ================================================// 调度器// ================================================static void startCleanupScheduler(void) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ fullCleanup(); ADBLog(@"[Clean] #1 done (0.5s)"); }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ fullCleanup(); ADBLog(@"[Clean] #2 done (1.5s)"); }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ fullCleanup(); ADBLog(@"[Clean] #3 done (3s)"); }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ fullCleanup(); ADBLog(@"[Clean] #4 done (6s)"); }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:YES block:^(NSTimer *timer) { fullCleanup(); }]; ADBLog(@"[Clean] periodic started (3s)"); }); [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ fullCleanup(); }); }]; });}// ================================================// 初始化入口 - 延迟激活 (避免黑屏)// ================================================__attribute__((constructor))static void AdBlockerInit(void) { ADBLog(@"[Init] v28.0 SystematicMode loading..."); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ [NSThread sleepForTimeInterval:0.1]; dispatch_async(dispatch_get_main_queue(), ^{ CFAbsoluteTime t0 = CFAbsoluteTimeGetCurrent(); %init(SDKShowGroup); %init(PlayerGroup); %init(URLGroup); %init(LabelGroup); startCleanupScheduler(); CFAbsoluteTime elapsed = CFAbsoluteTimeGetCurrent() - t0; ADBLog(@"[Init] v28.0 done in %.1fms", elapsed * 1000); ADBLog(@"[Init] SDKShow: %d classes", 9); ADBLog(@"[Init] Player: AVPlayer+AVQueuePlayer+AVPlayerVC+AVAudioPlayer"); ADBLog(@"[Init] URL: NSURL URLWithString"); ADBLog(@"[Init] Label: UILabel setText"); ADBLog(@"[Init] Cleanup: 0.5s/1.5s/3s/6s + 3s periodic"); }); });}