iOS安全与逆向工程:判断APP被重签名的有效解决方案

2024-11-29 0 377

在软件开发的今天,特别是在逆向工程这一领域,对软件包进行重签名检测和反检测,无疑是一项既具挑战性又充满乐趣的任务。一方面,这是为了确保软件的安全性而设计的检测系统;另一方面,逆向工程师们则不断尝试各种反检测方法。这两者之间的较量,无疑非常引人入胜。

包重签名检测原理

检查包内是否含有特定符号,比如“.”,这样的动作算是一种特别的检查起点。接着,分析描述文件中的“-”,通过比较签名数据来确认包是否被重新签名。在软件开发过程中,开发人员、调试员和逆向工程师在处理重签名时,都会用到描述文件。这种检测方法就像是一道门禁,只让拥有特定签名的“访客”进入。此外,相关代码编写简洁明了,遵循着读取文件、获取签名信息、进行比对等几个基本步骤,一旦发现信息不匹配,程序便会立即停止运行。

void checkCodeSign(NSString *identifier, NSString *teamId) {
#if defined __x86_64__ || __i386__ // 模拟器不需要生成embeded.mobileprovision文件来做真机调试的配置
    // do nothing
#else
    // 描述文件路径
    NSString *embeddedPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
    if (![[NSFileManager defaultManager] fileExistsAtPath:embeddedPath]) {
        return;
    }
    // 读取application-identifier  注意描述文件的编码要使用:NSASCIIStringEncoding
    NSString *embeddedProvisioning = [NSString stringWithContentsOfFile:embeddedPath encoding:NSASCIIStringEncoding error:nil];
    NSArray *embeddedProvisioningLines = [embeddedProvisioning componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
    for (int i = 0; i < embeddedProvisioningLines.count; i++) {
        if ([embeddedProvisioningLines[i] rangeOfString:@"application-identifier"].location != NSNotFound) {
            NSString *identifierString = embeddedProvisioningLines[i + 1]; // 类似:L2ZY2L7GYS.com.xx.xxx
            NSRange fromRange = [identifierString rangeOfString:@""];
            NSInteger fromPosition = fromRange.location + fromRange.length;
            NSInteger toPosition = [identifierString rangeOfString:@""].location;
            NSRange range;
            range.location = fromPosition;
            range.length = toPosition - fromPosition;
            NSString *fullIdentifier = [identifierString substringWithRange:range];
            NSScanner *scanner = [NSScanner scannerWithString:fullIdentifier];
            NSString *teamIdString;
            [scanner scanUpToString:@"." intoString:&teamIdString];
            NSRange teamIdRange = [fullIdentifier rangeOfString:teamIdString];
            NSString *appIdentifier = [fullIdentifier substringFromIndex:teamIdRange.length + 1];
            // 对比签名teamID或者identifier信息
            if (![appIdentifier isEqualToString:identifier] || ![teamId isEqualToString:teamIdString]) {
                // exit(0)
                asm(
                    "mov X0,#0n"
                    "mov w16,#1n"
                    "svc #0x80"
                    );
            }
            break;
        }
    }
#endif
}

在具体的项目操作中,尤其是中小型的iOS应用开发项目,若缺乏此类检测手段,将面临众多安全威胁。这些威胁可能包括公司知识产权遭受侵犯,用户隐私数据泄露等问题。因此,建立有效的检测机制显得尤为关键。

检测函数被hook的风险

检测函数种类繁多,相应地,其hook方法各异,这也给检测工作带来了潜在风险。例如,对于静态的C语言函数,若它们不涉及动态符号且未采用OC消息机制,常规的hook方法就不再适用。此时,我们只能借助特定的工具,如Dobby,来进行静态hook。若这些检测函数轻易被hook,那就像城堡的大门被不法之徒悄无声息地找到钥匙打开,相当危险。

换个角度来想,若检测函数遭受了hook,那么原本稳固的安全防线便如同破碎的墙垣,软件的整体安全性遭受了严重破坏。这种情况不仅会损害软件厂商的利益,还可能威胁到成千上万用户的数据安全。

cmake .. -G Xcode 
-DCMAKE_TOOLCHAIN_FILE=cmake/ios.toolchain.cmake 
-DPLATFORM=OS64 -DARCHS="arm64" -DCMAKE_SYSTEM_PROCESSOR=arm64 
-DENABLE_BITCODE=0 -DENABLE_ARC=0 -DENABLE_VISIBILITY=1 -DDEPLOYMENT_TARGET=9.3 
-DDynamicBinaryInstrument=ON -DNearBranch=ON -DPlugin.SymbolResolver=ON -DPlugin.Darwin.HideLibrary=ON -DPlugin.Darwin.Obj

Dobby静态hook的应用

Dobby工具对静态hook操作,特别是在处理OC函数和动态库中的C方法时,其原理较为直观,故无需详述。然而,对于某些特定的静态C函数,Dobby工具则展现出其独特价值。我们能够利用它,在特定项目中实施复杂的hook任务。比如,在某个与金融信息保护相关的iOS应用开发过程中,若需对特定检测函数实施静态hook,Dobby便成为一款出色的选择。

int DobbyHook(void *function_address, void *replace_call, void **origin_call);

实际操作中,要用好Dobby,必须按照既定步骤进行,这和操作精密仪器一样,要求非常严格。必须精确调整各项参数,以防操作不当造成钩子失效或触发其他系统风险。

编译生成包的注意事项

在编译生成包的过程中,正确操作同样不可忽视。我们可以模仿“WithiOS”的步骤创建一个工程,并使用Xcode进行编译。然而,在这个过程中,必须特别留意“cmake”命令的执行目录。比如,若存在子目录,直接在build目录下执行“cmake..”可能无法成功。以我自己的操作为例,多了一层子目录,这时必须将“cmake..”改为“cmake../..”,以确保正确定位到cmake配置目录。这虽是小事,但若疏忽,可能导致编译过程中出现错误,进而影响后续步骤。

void checkCodeSign(NSString *identifier, NSString *teamId); // 原来的方法
void (*originCheckCodeSign)(NSString *identifier, NSString *teamId); // 保留原始的方法实现的指针地址
void hookCheckCodeSign(NSString *identifier, NSString *teamId); // hook的方法
int main(int argc, char * argv[]) {
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        NSString * appDelegateClassName = NSStringFromClass([AppDelegate class]);
        BOOL isEncrypt = isEncrypted();
        NSLog(@"check is encrypt: %d", isEncrypt);
        // int DobbyHook(void *function_address, void *replace_call, void **origin_call);
        DobbyHook(checkCodeSign, hookCheckCodeSign, (void *)&originCheckCodeSign);
        checkCodeSign(@"hc.RuntimeLearning.demo", @"9D7EH8PVAX"); // security find-identity -v -p CodeSigning 可以获取到,也可以在导出ipa包的plist中查看
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
    }
}
void hookCheckCodeSign(NSString *identifier, NSString *teamId) {
    // do nothing
    NSLog(@"%s", __FUNCTION__);
}

在众多开发任务中,新手开发者往往因忽视这些小细节,耗费不少时间寻找错误,这无疑会减缓项目的推进速度。

函数指针存储原始实现

RuntimeLearning[8921:1837017] hookCheckCodeSign

我们可以设定一个新函数以及一个函数指针,以保存原始实现代码的指针位置。这个过程在编写代码时并不繁琐。尽管这个操作听起来较为复杂,但通过查看具体的代码示例,我们便能较为直观地理解它。这一做法相当于为原始函数配备了一个“备用方案”,在特定条件下,它能够对原始函数进行修复或替换等操作。

在复杂的软件逻辑里,若缺乏对原始实现指针地址的存储操作,一旦目标函数遭到改动或损坏,想要恢复其原始功能将会极其不易。

注入方式hook主包函数

在研究他人APP时,若要进行重签名和代码注入,会发现主包源码中无法直接编写hook代码。这时,动态注入技术变得尤为关键。这种技术能够修改主程序的MachO文件,并将我们编写的动态库嵌入其中。以获取目标函数地址为例,由于iOS的安全性措施,如ASLR可能导致函数地址发生偏移,因此必须准确计算出函数的真实地址,才能确保注入的正确性。

在APP逆向分析的实际操作中,这种注入手段能让我们轻松突破众多安全防护,从而更深入地审视程序功能,或发掘潜在的安全风险。

在此,我想向众多读者请教,在你们进行软件反向工程或进行安全防御的过程中,是否遇到过什么有趣的故事?期待大家的留言、点赞以及文章的转发。

#import "HCHook.h"
#import 
#import 
void (*originCheckCodeSign)(NSString *identifier, NSString *teamId); // 保留原始的方法实现的指针地址
void hookCheckCodeSign(NSString *identifier, NSString *teamId); // hook的方法
@implementation HCHook
+ (void)load {
    static uintptr_t checkCodeSignOffset = 0x1000164A0; // 这个偏移地址可以通过MachOView去查看
    uintptr_t mainASLR = _dyld_get_image_vmaddr_slide(0); // 获取主程序的aslr,因为checkCodeSign函数在主程序
    uintptr_t checkCodeSignAddress = mainASLR + checkCodeSignOffset;
    DobbyHook((void *)checkCodeSignAddress, hookCheckCodeSign, (void *)&originCheckCodeSign);
}
void hookCheckCodeSign(NSString *identifier, NSString *teamId) {
    // do nothing
    NSLog(@"%s", __FUNCTION__);
}
@end

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

七爪网 行业资讯 iOS安全与逆向工程:判断APP被重签名的有效解决方案 https://www.7claw.com/2798254.html

七爪网源码交易平台

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务