那些APP活动中的刷量与作弊

本文摘自《九阴真经:iOS黑客攻防秘籍》

当今移动互联网时代,平台中的App为了增加人气会搞一些优惠活动,但实际上,App的激活、注册、优惠活动都有可能被“刷”。刷量团队利用的方法就是修改手机的信息,让应用获取假的数据,认为老用户就是新的用户。苹果对隐私的保护使开发者不能获取UDID作为设备的唯一标识,所以识别设备的唯一标识的方法都是使用IDFA、OpenUDID以及其他的第三方平台提供的ID,而IDFA是可以在系统设置中进行重置的,OpenUDID和其他第三方平台提供的ID也都有可能被重置。如图9-1所示,是某第三方应用安装统计平台,通过重置ID和修改手机信息进行作弊,实现了刷量的目的,实际是一台手机,统计新增却是11台。

图像说明文字

由于将ID存放在沙盒中,应用被卸载掉,沙盒目录的数据会被清空,所以有些应用会将ID信息存在Keychain中,这样即使应用被卸载,数据也不会被清除,但在越狱环境下,Keychain也是可以清除的。

9.1 越狱环境下获取root权限

事实上,在已经越狱的iOS设备上使用Xcode编写的程序也是以mobile用户的身份运行,没有root权限,所以无法访问一些重要的文件和目录。

iOS的应用安装目录有两个,一个是/private/var/mobile/Containers/Bundle/Application,另一个是/Applications,前者存放使用Xcode安装或者在App Store上下载安装的应用,后者一般为系统自带的应用。如果想让应用以root身份运行,可以按以下的步骤来操作。

(1) 在应用的main函数添加如下代码:

setuid(0);
setgid(0);

(2) 将生成的应用上传到/Applications/yourApp.app。

(3) 这时桌面上没有图标,需要登录SSH运行uicache命令,该命令经常用于修复没有图标的问题。

(4) 执行chown root yourApp,更改所有者为root。

(5) 切换到应用的目录,运行chmod u+s yourApp。

这时在手机上点击你的应用,通过ps aux命令查看进程运行的用户就是root,而不是mobile。

(6) 以上方法在iOS 8系统没有问题,如果是iOS 9和iOS 10就得再多一个步骤,由于iOS 9安全限制,不允许具有root权限的应用启动,启动之后,你会发现马上就退出了。可以给原来应用的可执行文件改名,比如改为yourApp_,然后再新建一个yourApp名称的脚本并使用chmod的755命令设置可执行权限。脚本内容如下:

#!/bin/bash
root=$(dirname "$0")
exec "${root}"/yourApp_

相当于yourApp脚本执行之后,会执行yourApp_,这样就正常可以启动了。

9.2 修改手机信息

通过修改手机的信息可以“刷”应用的安装量,可以修改的信息有很多种,其中常见的有UDID、序列号、MAC地址、蓝牙地址、系统版本、机器名称、IDFA、IDFV、SSID、BSSID、DeviceToken、位置信息等。

9.2.1 修改基本信息

修改硬件信息常用的方法是hook MGCopyAnswer,在第6章讲解MSHookFuncation时提到,可以通过hook MGCopyAnswer实现修改本机的序列号。本节有两个目标,一是修改硬件相关的信息,二是修改系统版本、机型、IDFA、IDFV。

首先使用Theos新建工程,命令和参数如下:

exchen$ export THEOS=/opt/theos
exchen$ /opt/theos/bin/nic.pl
NIC 2.0 - New Instance Creator
------------------------------
  ......
  [11.] iphone/tweak
Choose a Template (required): 11
Project Name (required): ChangeiPhoneInfo
Package Name [com.yourcompany.changeiphoneinfo]: net.exchen.ChangeiPhoneInfo
Author/Maintainer Name [boot]: exchen
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.Preferences
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: Preferences
Instantiating iphone/tweak in changeiphoneinfo/...

然后编写如下代码:

#include <substrate.h>
#import <sys/utsname.h>

static CFTypeRef (*orig_MGCopyAnswer)(CFStringRef str);
static CFTypeRef (orig_MGCopyAnswer_internal)(CFStringRef str, uint32_t outTypeCode);
static int (*orig_uname)(struct utsname *);

CFTypeRef new_MGCopyAnswer(CFStringRef str);
CFTypeRef new_MGCopyAnswer_internal(CFStringRef str, uint32_t* outTypeCode);
int new_uname(struct utsname *systemInfo);

int new_uname(struct utsname * systemInfo){

NSLog(@"new_uname");
int nRet = orig_uname(systemInfo);

char str_machine_name[100] = "iPhone8,1";
strcpy(systemInfo-&gt;machine,str_machine_name);

return nRet;

}

CFTypeRef new_MGCopyAnswer(CFStringRef str){

//NSLog(@"new_MGCopyAnswer");
//NSLog(@"str: %@",str);

NSString *keyStr = (__bridge NSString *)str;
if ([keyStr isEqualToString:@"UniqueDeviceID"] ) {

    NSString *strUDID = @"57359dc2fa451304bd9f94f590d02068d563d283";
    return (CFTypeRef)strUDID;
}
else if ([keyStr isEqualToString:@"SerialNumber"] ) {

    NSString *strSerialNumber = @"DNPJD17NDTTP";
    return (CFTypeRef)strSerialNumber;
}
else if ([keyStr isEqualToString:@"WifiAddress"] ) {

    NSString *strWifiAddress = @"98:FE:94:1F:30:0A";
    return (CFTypeRef)strWifiAddress;
}
else if ([keyStr isEqualToString:@"BluetoothAddress"] ) {

    NSString *strBlueAddress = @"98:FE:94:1F:30:0A";
    return (CFTypeRef)strBlueAddress;
}
else if([keyStr isEqualToString:@"ProductVersion"]) {

    NSString *strProductVersion = @"10.3.3";
    return (CFTypeRef)strProductVersion;
}
else if([keyStr isEqualToString:@"UserAssignedDeviceName"]) {

    NSString *strUserAssignedDeviceName = @"exchen's iPhone";
    return (CFTypeRef)strUserAssignedDeviceName;
}
return orig_MGCopyAnswer(str);

}

CFTypeRef new_MGCopyAnswer_internal(CFStringRef str, uint32_t* outTypeCode) {

//NSLog(@"new_MGCopyAnswer_internal");
//NSLog(@"str: %@",str);

NSString *keyStr = (__bridge NSString *)str;
if ([keyStr isEqualToString:@"UniqueDeviceID"] ) {

    NSString *strUDID = @"57359dc2fa451304bd9f94f590d02068d563d283";
    return (CFTypeRef)strUDID;
}
else if ([keyStr isEqualToString:@"SerialNumber"] ) {

    NSString *strSerialNumber = @"DNPJD17NDTTP";
    return (CFTypeRef)strSerialNumber;
}
else if ([keyStr isEqualToString:@"WifiAddress"] ) {

    NSString *strWifiAddress = @"98:FE:94:1F:30:0A";
    return (CFTypeRef)strWifiAddress;
}
else if ([keyStr isEqualToString:@"BluetoothAddress"] ) {

    NSString *strBlueAddress = @"98:FE:94:1F:30:0A";
    return (CFTypeRef)strBlueAddress;
}
else if([keyStr isEqualToString:@"ProductVersion"]) {

    NSString *strProductVersion = @"10.3.3";
    return (CFTypeRef)strProductVersion;
}
else if([keyStr isEqualToString:@"UserAssignedDeviceName"]) {

    NSString *strUserAssignedDeviceName = @"exchen's iPhone";
    return (CFTypeRef)strUserAssignedDeviceName;
}

return orig_MGCopyAnswer_internal(str, outTypeCode);

}

void hook_uname(){

NSLog(@"hook_uname");
char str_libsystem_c[100] = {0};
strcpy(str_libsystem_c, "/usr/lib/libsystem_c.dylib");

void *h = dlopen(str_libsystem_c, RTLD_GLOBAL);
if(h != 0){

    MSImageRef ref = MSGetImageByName(str_libsystem_c);
    void * unameFn = MSFindSymbol(ref, "_uname");
    NSLog(@"unameFn");
    MSHookFunction(unameFn, (void *) new_uname, (void **)&amp; orig_uname);
}
else {

    strcpy(str_libsystem_c, "/usr/lib/system/libsystem_c.dylib");
    h = dlopen(str_libsystem_c, RTLD_GLOBAL);
    if(h != 0){

        MSImageRef ref = MSGetImageByName(str_libsystem_c);
        void * unameFn = MSFindSymbol(ref, "_uname");
        NSLog(@"unameFn");
        MSHookFunction(unameFn, (void *) new_uname, (void **)&amp; orig_uname);
    }
    else {

        NSLog(@"%s dlopen error", str_libsystem_c);
    }
}

}

void hookMGCopyAnswer(){

char *dylib_path = (char*)"/usr/lib/libMobileGestalt.dylib";
void *h = dlopen(dylib_path, RTLD_GLOBAL);
if (h != 0) {

    MSImageRef ref = MSGetImageByName([strDylibFile UTF8String]);
    void * MGCopyAnswerFn = MSFindSymbol(ref, "_MGCopyAnswer");

    //64位特征码
    uint8_t MGCopyAnswer_arm64_impl[8] = {0x01, 0x00, 0x80, 0xd2, 0x01, 0x00, 0x00, 0x14};
    //10.3特征码
    uint8_t MGCopyAnswer_armv7_10_3_3_impl[5] = {0x21, 0x00, 0xf0, 0x00, 0xb8}; 

    //处理64位系统
    if (memcmp(MGCopyAnswerFn, MGCopyAnswer_arm64_impl, 8) == 0) {

        MSHookFunction((void*)((uint8_t*)MGCopyAnswerFn + 8), (void*)new_MGCopyAnswer_internal, 
            (void**)&amp;orig_MGCopyAnswer_internal);
    }
    //处理32位10.3到10.3.3系统
    else if(memcmp(MGCopyAnswerFn, MGCopyAnswer_armv7_10_3_3_impl, 5) == 0){

        MSHookFunction((void*)((uint8_t*)MGCopyAnswerFn + 6), (void*)new_MGCopyAnswer_internal, 
            (void**)&amp;orig_MGCopyAnswer_internal);
    }
    else{

        MSHookFunction(MGCopyAnswerFn, (void *) new_MGCopyAnswer, (void **)&amp;orig_MGCopyAnswer);
    }  
}

}

%hook ASIdentifierManager
//IDFA
-(NSUUID*)advertisingIdentifier{

NSUUID *uuid = [[NSUUID alloc] init];
return uuid;

}
%end

%hook UIDevice

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值