gengjf025 发表于 2017-3-30 10:49:02

【非越狱环境】钉钉躺床上打卡之水印篇

钉钉iOS客户端签到图片修改(非越狱环境)

本文续自上一篇:【非越狱环境】钉钉躺床上打卡之WIFI篇(https://www.chinapyg.com/forum.php?mod=viewthread&tid=89902)

一、背景最近一直有朋友抱怨外勤人员不仅要移动打卡,还要每天在考勤地上传一张照片,照片上有位置信息、日期信息等水印,如果可以提前多拍几张图片,以后每天选一张用于签到岂不是很high?顺手抽空处理了一下,最终实现从相册中随便选取照片,签到拍摄照片时直接替换掉,确保水印被打在相册中选取的那张图片上并上传。
二、工具准备见上一篇。
三、分析看了钉钉的签到拍照的界面,因为在图片上增加了位置信息和日期等水印,而且自定义了拍摄的UI,所以通用的技术是对AVFoundation框架下的AVCaptureStillImageOutput类下手,该类获取摄像头图片的方式是jpegStillImageNSDataRepresentation:,此方法理论上对所有app通用有效。
四、编码
    我们在上一篇的代码基础上增加签到信息修改的相关代码,从相册选取图片的代码就不重复写了,直接github上搞了个:QBImagePickerController1、创建一个类DTCameraSettingViewController用于选取相册中的图片,代码如下:#import "DTCameraSettingViewController.h"

#import "QBImagePickerController.h"

#import "JF_Helper.h"

#import "UIImage+JFUtil.h"

#import "ALAsset+JFUtil.h"

#import "DTCameraHook.h"

static NSString *image_base64_button = @"iVBORw0KGgoAAAANSUhEUgAAALQAAABACAYAAACzzl09AAAAAXNSR0IArs4c6QAA\
AAlwSFlzAAAWJQAAFiUBSVIk8AAAABxpRE9UAAAAAgAAAAAAAAAgAAAAKAAAACAA\
AAAgAAACF+d7zw0AAAHjSURBVHgB7JixTcNQFEVdUbEJA5AABWIH9qKgyg4YRB8x\
hVdggQzw+c/EN0oq3yq3OEiIG+k9c3VyYn1nGC5+Hr/b3fazvW3GNm3Hdth8tMYv\
DFIcmJ0sN7uj5eqFvqeXr1O76cPvKcXpwYdojQPlbLl7Mrmno8x7XWBsu6evdv/8\
027PBnkBgSsTKCfLzX6C2C2+dqn3Z1Ivd+b+9/dhbC9X7sy/h8AqAuVqOVtil8Pz\
Up1DFtOReRVHhoIIlLOLv/OZen4ArAe/fgsP6kkVCKwmsBw/yuWhvs0ow+tcsvoK\
DEIgiMB8pv6/KU9DP3vMX83xABj0DlHFIlDuHs/Rh2E5f1hXYBgCYQTksUJYQepA\
wCEgjxWcbWYhEEZAHiuEFaQOBBwC8ljB2WYWAmEE5LFCWEHqQMAhII8VnG1mIRBG\
QB4rhBWkDgQcAvJYwdlmFgJhBOSxQlhB6kDAISCPFZxtZiEQRkAeK4QVpA4EHALy\
WMHZZhYCYQTksUJYQepAwCEgjxWcbWYhEEZAHiuEFaQOBBwC8ljB2WYWAmEE5LFC\
WEHqQMAhII8VnG1mIRBGQB4rhBWkDgQcAvJYwdlmFgJhBOSxQlhB6kDAISCPFZxt\
ZiEQRkAeK4QVpA4EHAKLx38AAAD//zKoC3IAAAGsSURBVO2YsU0DQRQFLyKiEwrA\
BgJED/RF4Mg9cCByiyrcghuggGX/6jwyooF78liy9E528P5ovPrrafPeWr0nXxII\
JoDHhOBhrC4BPCbIRALBBPCYEDyM1SWAxwSZSCCYAB4TgoexugTwmCATCQQTwGNC\
8DBWlwAeE2QigWACeEwIHsbqEsBjgkwkEEwAjwnBw1hdAnhMkIkEggngMSF4GKtL\
AI8JMpFAMAE8JgQPY3UJ4DFBJhIIJoDHhOBhrC4BPCbIRALBBPCYEDyM1SWAxwSZ\
SCCYAB4TgoexugTwmCATCQQTwGNC8DBWlwAeb+f2Uw/P3+1WLBJIJFDulsPl8rSZ\
27Eenj7bfeIwdpZAuTtO6O7ytP1ob8vDXjQSSCTQD+X9OKG7y9PjV7sbQvdT+mFu\
L4kD2fl6CZSzZ3/L5UGi7x67YfjcTkp9vXKkTV6udndPi7s7+r8e203/4HA2vY7w\
2ku8KILIsBIC5eTYmZc1Y5H5UA7/qbhIPU5qxO5riFkGa3agtot/Ml+aXXvIuCj2\
G2P/8vhLb80D2e26fnDDyXKzXwDZmS8E/gW5cu3DvOjXFwAAAABJRU5ErkJggg==";

@interface DTCameraSettingViewController () <QBImagePickerControllerDelegate>

@property (nonatomic, strong) NSMutableArray *array_photos;

@property (nonatomic, strong) UIImageView *imageView_photo;

@property (nonatomic, strong) UIButton *button_clean;

@property (nonatomic, strong) UIButton *button_commit;

@end

@implementation DTCameraSettingViewController

- (void)viewDidLoad {
    ;
   
    self.array_photos = ;
   
    UIImage *image = ;
   
    if(image) {
      
      ;
    }
   
    ;
}

- (void)makeSubviews {
   
    self.navigationItem.leftBarButtonItem = [ initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(cancel:)];
   
    self.navigationItem.rightBarButtonItem = [ initWithTitle:@"选取" style:UIBarButtonItemStylePlain target:self action:@selector(selectPhotos:)];
   
    self.view.backgroundColor = ;
   
    _imageView_photo = [ init];
    _imageView_photo.frame = CGRectMake(0, 80, .bounds.size.width, 200);
    ;
   
    NSData *decodedImageData = [ initWithBase64EncodedString:image_base64_button options:NSDataBase64DecodingIgnoreUnknownCharacters];
    UIImage *decodedImage = ;
   
    self.button_clean = ;
    self.button_clean.frame = CGRectMake(25, _imageView_photo.frame.origin.y + _imageView_photo.frame.size.height + 15, 125, 44);
    forState:UIControlStateNormal];
    self.button_clean.titleLabel.font = ;
    forState:UIControlStateNormal];
    ;
    ;
    self.button_clean.hidden = YES;
    ;
   
    self.button_commit = ;
    self.button_commit.frame = CGRectMake(self.button_clean.frame.origin.x + self.button_clean.frame.size.width + 20, self.button_clean.frame.origin.y, 125, 44);
    forState:UIControlStateNormal];
    self.button_commit.titleLabel.font = ;
    ;
    ;
    ;
    self.button_commit.hidden = YES;
    ;
   
    ;
}

- (void)updatePhoto {
   
    if(self.array_photos && > 0) {
      
      self.button_clean.hidden = NO;
      
      self.button_commit.hidden = NO;
      
      UIImage *image = ;
      
      self.imageView_photo.image = ;
      
      self.button_clean.hidden = NO;
      
      self.button_commit.hidden = NO;
    }
    else {
      
      self.imageView_photo.image = nil;
      
      self.button_clean.hidden = YES;
      
      self.button_commit.hidden = YES;
    }
}

#pragma mark - QBImagePickerControllerDelegate

- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(ALAsset *)asset {
   
    ;
   
    UIImage *image = ;
   
    NSData *data = UIImagePNGRepresentation(image);
    image = ;
   
    ;
   
    ;
   
    ;
}

- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAssets:(NSArray *)assets {
   
    ;
   
    for (ALAsset *asset in assets) {
      
      UIImage *image = ;
      
      ;
    }
   
    ;
   
    ;
}

- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController {
   
    ;
}

#pragma mark -

- (void)cancel:(id)sender {
   
    ;
}

- (void)selectPhotos:(id)sender {
   
    QBImagePickerController *imagePickerController = [ init];
    imagePickerController.delegate = self;
    imagePickerController.filterType = QBImagePickerControllerFilterTypePhotos;
    imagePickerController.allowsMultipleSelection = YES;
    imagePickerController.minimumNumberOfSelection = 1;
    imagePickerController.maximumNumberOfSelection = 1;
    ;
}

- (void)cleanPhoto:(id)sender {
   
    ;
   
    [ removeItemAtPath:jf_photoPath error:nil];
   
    ;
}

- (void)commit:(id)sender {
   
    if(self.array_photos && > 0) {
      
      UIImage *image = ;
      
      ;
    }
   
    ;
}

@end
2、类DTCameraHook用户存储选取的图片和hook类AVCaptureStillImageOutput,代码如下:.h文件#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>

#define jf_photoDirectory

#define jf_photoName @"jf_photo.png"

#define jf_photoPath

@interface DTCameraHook : NSObject

+ (void)hookCameraWith:(UIImage *)image;

@end.m文件#import "DTCameraHook.h"
#import "UIImage+JFUtil.h"

#import "JF_Helper.h"

#import "AVCaptureStillImageOutput+JFUtil.h"

@interface DTCameraHook ()

@end

@implementation DTCameraHook

+ (void)createPhotoDirectory {
   
    NSFileManager *fileManager = ;
   
    // 创建录音文件存放目录
    [fileManager createDirectoryAtPath:jf_photoDirectory
         withIntermediateDirectories:YES
                            attributes:nil
                                 error:nil];
}

+ (void)hookCamera {
   
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      
      _jf_Hook_Class_Method(NSClassFromString(@"AVCaptureStillImageOutput"), NSSelectorFromString(@"jpegStillImageNSDataRepresentation:"), NSClassFromString(@"AVCaptureStillImageOutput"), NSSelectorFromString(@"jf_jpegStillImageNSDataRepresentation:"));
    });
}

+ (void)hookCameraWith:(UIImage *)image {
   
    if(!image) return;
   
    ;
   
    ;
}

+ (void)load {
   
    // 创建图片目录
    ;
   
    ;
}

@end

五、注入、打包、签名操作步骤同上一篇,安装测试:
可以看到成功替换了图片,此功能对所有拍照都有影响,所以签到完成之后需要把设置的签到图片清除,下次签到时再提前设置好即可。
六、代码地址**** Hidden Message *****七、结束语好好上班,谨慎使用!

小锤子起钉儿 发表于 2017-3-30 12:33:15

大神牛叉叉,有成品不?

nociabx 发表于 2017-3-30 17:51:02

好好上班,谨慎使用!哈哈!

0xcb 发表于 2017-3-31 08:40:21

看来钉钉号称的安全级别是通信过程高

左耳 发表于 2017-3-31 09:38:06

谢谢分享

qientin085 发表于 2017-3-31 10:46:24

厉害了,又出新了。

hu007 发表于 2017-3-31 16:21:20

我单位可能也要使用钉钉了{:curse:}

gengjf025 发表于 2017-3-31 17:55:27

hu007 发表于 2017-3-31 16:21
我单位可能也要使用钉钉了

那你该庆幸再也不用早起了

斌哥 发表于 2017-4-5 10:30:10

来膜拜大神

gengjf025 发表于 2017-4-6 11:46:28

zaq111 发表于 2017-4-6 11:33
听说最近容易被后台检测到异常
我这边有朋友用了半年了还没出现问题,不过还是要谨慎使用,好好上班
页: [1] 2 3 4 5
查看完整版本: 【非越狱环境】钉钉躺床上打卡之水印篇