IOS multi open detection, anti multi open detection, anti anti multi open detection
NSBundle.mainBundle.bundleIdentifier;
[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSBundle.mainBundle.infoDictionary[@"CFBundleIdentifier"];
[NSDictioanry dictionaryWithContentsOfFile:@"Info.plist"][@"CFBundleIdentifier"]
#include <dlfcn.h>
BOOL MUIsCallFromQQ() {
NSArray *address = [NSThread callStackReturnAddresses];
Dl_info info = {0};
if(dladdr((void *)[address[2] longLongValue], &info) == 0) return NO;
NSString *path = [NSString stringWithUTF8String:info.dli_fname];
if ([path hasPrefix:NSBundle.mainBundle.bundlePath]) {
//Binary from the ipa package
if ([path.lastPathComponent isEqualToString:@"MyPlugin.dylib"]) {
//Binary is the plug-in itself
return NO;
} else {
//Binary is QQ
return YES;
}
} else {
//Binary is the system or jailbreak plug-in
return NO;
}
}
//Take - (NSString *) bundleIdentifier as an example
%hook NSBundle
//Take - (NSString *) bundleIdentifier as an example
%hook NSBundle
- (NSString *)bundleIdentifier{
if (MUIsCallFromWeChat()) {
NSString *str = @"com.tencent.mqq";
return str;
}
return %orig;
}
%hook QQAddressBookAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
%orig;
NSDictionary *dic = [[NSBundle mainBundle]infoDictionary];
[dic setValue:@"com.tencent.mqq" forKey:@"CFBundleIdentifier"];
return YES;
}
%end
How to detect multiple opening
NSBundle.mainBundle.bundleIdentifier;
[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSBundle.mainBundle.infoDictionary[@"CFBundleIdentifier"];
[NSDictioanry dictionaryWithContentsOfFile:@"Info.plist"][@"CFBundleIdentifier"]
How to de detect multiple opening
1. No multiple opening detected
info[@"CFBundleIdentifier"]; // - [NSDictionary objectForKeyedSubscript:]
[info objectForKey:@"CFBundleIdentifier"];
[info valueForKey:@"CFBundleIdentifier"];
/*
*Assume that the Bundle Identifier value of the current avatar is com. unique. xin
*/
#import <Foundation/Foundation.h>
#define CFBundleIdentifier @"CFBundleIdentifier"
#define ORIG_VALUE @"com.tencent.xin"
#define REAL_VALUE @"com.unique.xin"
/*
*The - [NSBundle bundleIdentifier] method is eliminated here
*/
MUHInstanceImplementation(NSBundle, bundleIdentifier, NSString *) {
NSString *orig = MUHOrig(NSBundle, bundleIdentifier);
if ([orig isEqualToString:REAL_VALUE]) {
orig = ORIG_VALUE;
}
return orig;
}
/*
*The - [NSBundle objectForInfoDictionaryKey:] method is eliminated here
*
*MUHInstanceImplementation annotation: define the implementation body of a hook
*The first parameter is the class to hook
*The second parameter is the method name, which will be used in the following MUHMain and MUHORig. It can be inconsistent with the actual method name, but it must be unique
*The third parameter is the return value type
*The fourth and subsequent parameters are the actual parameter table of the Hook method.
*
*If you want to hook a Class Method, such as+[UIImage imageNamed]
*Please use MUHClassImplementation, the specific usage is the same as above
*/
MUHInstanceImplementation(NSBundle, objForInfoKey, id, NSString *key) {
/*
*MUHORig comment: call the original method
*The first parameter is the class of the original method
*The second parameter is the method name
*The third and subsequent parameters are the actual parameters passed in
*/
NSString *orig = MUHOrig(NSBundle, objForInfoKey, key);
if ([key isKindOfClass:[NSString class]]) {
if ([key isEqualToString:CFBundleIdentifier]) {
if ([orig isEqualToString:REAL_VALUE]) {
orig = ORIG_VALUE;
}
}
}
return orig;
}
MUHInstanceImplementation(NSBundle, infoDictionary, NSDictionary *) {
NSMutableDictionary *info = [MUHOrig(NSBundle, infoDictionary) mutableCopy];
if (self == NSBundle.mainBundle) {
info[CFBundleIdentifier] = REAL_VALUE;
}
return [info copy];
}
MUHInstanceImplementation(NSDictionary, objectForKey, id, NSString *key) {
id orig = MUHOrig(NSDictionary, objectForKey, key);
if ([key isKindOfClass:[NSString class]]) {
if ([key isEqualToString:CFBundleIdentifier]) {
if ([orig isEqualToString:REAL_VALUE]) {
id = ORIG_VALUE;
}
}
}
return orig
}
MUHInstanceImplementation(NSDictionary, valueForKey, id, NSString *key) {
id orig = MUHOrig(NSDictionary, valueForKey, key);
if ([key isKindOfClass:[NSString class]]) {
if ([key isEqualToString:CFBundleIdentifier]) {
if ([orig isEqualToString:REAL_VALUE]) {
id = ORIG_VALUE;
}
}
}
return orig
}
MUHInstanceImplementation(NSDictionary, objectForKeyedSubscript, id, NSString *key) {
id orig = MUHOrig(NSDictionary, objectForKeyedSubscript, key);
if ([key isKindOfClass:[NSString class]]) {
if ([key isEqualToString:CFBundleIdentifier]) {
if ([orig isEqualToString:REAL_VALUE]) {
id = ORIG_VALUE;
}
}
}
return orig
}
/*
*MUHMain comment: define a function with the constructor attribute.
*When Dyld loads this binary file into memory, it will automatically call this function to complete the hook work before running
*/
void MUHMain() {
/*
*MUHHookInstanceMessage Note: Make an instance hook implementation defined above effective
*The first parameter is the class of the above implementation body
*The second parameter is the method name obtained by the above implementation body
*The third parameter is the corresponding SEL
*
*If you want a Class Hook to take effect, you can use
* MUHHookClassMessage()
*Same as above
*/
MUHHookInstanceMessage(NSBundle, bundleIdentifier, bundleIdentifier);
MUHHookInstanceMessage(NSBundle, infoDictionary, infoDictionary);
MUHHookInstanceMessage(NSBundle, objectForInfoDictionaryKey, objectForInfoDictionaryKey:);
MUHHookInstanceMessage(NSDictionary, objectForKey, objectForKey:);
MUHHookInstanceMessage(NSDictionary, valueForKey, valueForKey:);
MUHHookInstanceMessage(NSDictionary, objectForKeyedSubscript, objectForKeyedSubscript:);
}
#import <UIKit/UIKit.h>
#import <AdSupport/AdSupport.h>
MUHInstanceImplementation(ASIdentifierManager, advertisingIdentifier, NSUUID *) {
NSString *idfa = [userDefaults stringForKey:@"com.unique.idfa"];
if(! idfa)
{
idfa = [NSUUID UUID]. UUIDString;
[userDefaults setObject:idfa forKey:@"com.unique.idfa"];
[userDefaults synchronize];
}
NSUUID *udid = [[NSUUID alloc] initWithUUIDString:idfa];
return udid;
}
/*
*Forcibly return a popular name that is not easily suspected
*/
MUHInstanceImplementation(UIDevice, name, NSString *) {
return @"iPhone";
}
void MUHMain() {
MUHHookInstanceMessage(ASIdentifierManager, advertisingIdentifier, advertisingIdentifier);
MUHHookInstanceMessage(UIDevice, name, name);
}
2. Only make WeChat unable to detect multiple opening
#include <dlfcn.h>
BOOL MUIsCallFromWeChat() {
NSArray *address = [NSThread callStackReturnAddresses];
Dl_info info = {0};
if(dladdr((void *)[address[2] longLongValue], &info) == 0) return NO;
NSString *path = [NSString stringWithUTF8String:info.dli_fname];
if ([path hasPrefix:NSBundle.mainBundle.bundlePath]) {
//Binary from the ipa package
if ([path.lastPathComponent isEqualToString:@"MyPlugin.dylib"]) {
//Binary is the plug-in itself
return NO;
} else {
//Binary is WeChat
return YES;
}
} else {
//Binary is the system or jailbreak plug-in
return NO;
}
}
//Take - [NSBundle bundleIdentifier] as an example, and extend the rest by yourself
MUHInstanceImplementation(NSBundle, bundleIdentifier, NSString *) {
NSString *orig = MUHOrig(NSBundle, bundleIdentifier);
if (MUIsCallFromWeChat() == NO) {
return orig;
}
if ([orig isEqualToString:REAL_VALUE]) {
orig = ORIG_VALUE;
}
return orig;
}
How to cancel anti detection multiple opening
1. Use CoreFoundation detection (not necessarily reliable)
2. Use Appex and Watch for detection (not necessarily reliable)
3. Use FILE+encryption+confusion detection (I think it's reliable)
#Define EncryptStr (str) str//Encryption algorithm
#Define DecryptStr (str) str//Decryption algorithm
static BOOL ZheBuShiYiGeDuoKaiJianCe()
int result = 1;
NSString * filePath=[NSBundle. mainBundle. bundlePath stringByAppendingPathComponent: DecryptStr (@ "Write dead encrypted Info. plist here");
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:filePath];
filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"temp.txt"];
[dictionary writeToFile:filePath atomically:YES];
//I don't know why the Info.plist in the Demo cannot be read directly by UTF8. It must be read and written by the dictionary.
//There may be a vulnerability here. You can directly hook - [NSDictionary dictionary WithContentsOfFile:]
//But I don't know why I can't read it directly. If God knows, he can guide me.
unsigned long long size = [NSFileManager.defaultManager attributesOfItemAtPath:filePath error:nil].fileSize;
FILE *file = fopen(filePath.UTF8String, "r");
if (file != NULL) {
char *content = malloc(size + 1); memset(content, 0, size + 1);
fread(content, size, sizeof(char), file);
Char * beginIndex=strstr (content, DecryptStr ("write CFBundleIdentifier of dead encryption here"));
BeginIndex=strstr (beginIndex, DecryptStr ("write the encrypted<string>here"))+8;
if (beginIndex != NULL) {
Char * endIndex=strstr (beginIndex, DecryptStr ("write here for dead encryption</string>"));
if (endIndex != NULL) {
unsigned long bidsize = endIndex - beginIndex;
char *endbid = malloc(bidsize + 1); memset(content, 0, bidsize + 1);
strlcpy(endbid, beginIndex, bidsize + 1);
Result=strcmp (EncryptStr (endbid), "Write the dead encrypted BundleID here");
//The encrypted BundleID is directly compared here, because strcmp may also be hooked.
free(endbid);
}
}
free(content);
beginIndex = content = NULL;
fclose(file);
}
printf("%d\n", result);
return result == 0;
}