【问题标题】:How do I detect if an app has been cracked without examining the SignerIdentity?如何在不检查 SignerIdentity 的情况下检测应用程序是否已被破解?
【发布时间】:2012-09-28 06:20:26
【问题描述】:

曾经有一种方法可以检查应用程序是否从 App Store 购买,以防止被破解:

NSBundle *bundle = [NSBundle mainBundle]; 
NSDictionary *info = [bundle infoDictionary]; 
if ([info objectForKey: @"SignerIdentity"] != nil) 
{ /* do something */  }

但是这种方法不再有效,因为破解者已经找到了改变 Info.plist 的方法。我知道this older question,但那里提供的答案依赖于上述技术,该技术不再有效。

如何在不读取 Info.plist 中的 SignerIdentity 的情况下检测您的应用程序是否被破解或从 App Store 合法购买?

【问题讨论】:

  • 澄清一下...您想知道您的应用程序是否安装在 App Store 以外的设备上? (例如,通过开发者渠道还是非法?)
  • +1 表示希望看到最新的答案。重复的答案和编辑后的答案都是 2009 年的!
  • 老实说,不要打扰。首先,破解者有很多新技术可以绕过这些东西,所以他们总是领先一步,最重要的是,一开始可能不值得。我的一些非开发人员朋友盗版了东西,他们要么免费获得,要么不获得。如果他们安装了一个应用程序并显示“这个应用程序是盗版的,请从应用商店购买”,他们只会删除它。
  • 在对先前问题的投票最高的答案以及对该答案的更新中,提到了另一种技术作为替代 Info.plist 检查的首选技术:@ 987654322@。这种方法是否也不再有效?
  • 我曾经读过 Rovio 开发人员的一篇文章,说花时间对抗黑客比不理会它会损失更多的钱。更重要的是,盗版可能会为您的应用带来一些新用户。他们免费下载并使用它,如果他们喜欢它,他们可能会将它推荐给以后会购买您的应用程序的非盗版者。 @Greg 所说的也是正确的。我有一个越狱设备,并购买 Skype。当我启动它时,我有一个很棒的 UIAlertView 说这个应用程序不能在越狱设备上运行,然后终止该应用程序。喜欢它。

标签: ios iphone ipad app-store


【解决方案1】:

虽然不是检查应用程序是否是从 App Store 购买的,但我使用此代码检查我的应用程序是否在越狱设备上运行:

+(BOOL)isJailbroken { 
    NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"]; 
    return [[UIApplication sharedApplication] canOpenURL:url]; 
} 

【讨论】:

  • 不是最佳答案,因为并非所有越狱者都是海盗。如果有人为您的应用付费,但由于越狱而导致应用崩溃,这会激怒他们。
  • 但是“Icy”和“Installer”呢?
  • Greg,我的代码不会使应用程序崩溃,它只是检查 URL 是否可以打开,即 URL 方案已在设备上注册。
【解决方案2】:

我个人喜欢 Mick 的回答,因为它简短而简单。

Greg 的响应无效 - Mick 的代码仅检查应用程序是否可以打开该 URL,因此应该不会崩溃。

我已经在我的一个应用程序中实现了以下功能,之前它会更严格地检查应用程序是否加密,如果不是,则很可能是破解的应用程序:

从分析结果来看,这种方法为我防止了成千上万的盗版用户,并且可能需要 5 分钟来实施,所以这样做的成本几乎为零——对我来说,我不在乎它是否会增加销售额(我当时是肯定它无论如何都不会发生——更重要的是,我不希望人们从我的辛勤工作中白白浪费)。此外,我的应用程序的大量内容在确定应用程序是否为盗版后提供信息,如果是,则返回垃圾数据。

在 main.m 中

#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <TargetConditionals.h>

#if TARGET_IPHONE_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
#define LC_ENCRYPTION_INFO 0x21
struct encryption_info_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint32_t cryptoff;
    uint32_t cryptsize;
    uint32_t cryptid;
};
#endif

static BOOL isEncrypted();

static BOOL isEncrypted () {
    const struct mach_header *header;
    Dl_info dlinfo;

    /* Fetch the dlinfo for main() */
    if (dladdr(main, &dlinfo) == 0 || dlinfo.dli_fbase == NULL) {
        //NSLog(@"Could not find main() symbol (very odd)");
        return NO;
    }
    header = dlinfo.dli_fbase;

    /* Compute the image size and search for a UUID */
    struct load_command *cmd = (struct load_command *) (header+1);

    for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++) {
        /* Encryption info segment */
        if (cmd->cmd == LC_ENCRYPTION_INFO) {
            struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) cmd;
            /* Check if binary encryption is enabled */
            if (crypt_cmd->cryptid < 1) {
                /* Disabled, probably pirated */
                return NO;
            }

            /* Probably not pirated <-- can't say for certain, maybe theres a way around it */
            return YES;
        }

        cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
    }

    /* Encryption info not found */
    return NO;
}

【讨论】:

  • 这会返回我从 xCode 开始的应用程序的“否”。正常吗?
  • @Altaveron 这很正常。仅当您从 appstore 启动应用程序时,它才会返回 YES。当您将 ipa 交给 Apple 时,它​​会加密并签署应用程序。 Debug 和 AdHoc 构建将始终不加密,而 Appstore 构建 - 加密。
  • 在应用程序被发送到AppStore之前如何测试代码?
  • 苹果在审核时是否使用了未加密版本的应用?如果是这样,它可能会向他们显示错误的内容并让您的应用被拒绝..
  • 你能分享一下它的 swift 版本吗?
【解决方案3】:

我建议使用更小的代码 sn-p,它与@user1353482 建议的功能相同(并且方式相同)。我会用 cmets 写,但那时代码将不可读。此外,我可能是错的,但似乎即使在为模拟器编译时也不再需要额外的定义(至少这在 xcode 4.5.1 中有效,目标是 5.0)。

请注意,此代码在调试和临时二进制文件中返回 false,但我们谈论的是应用商店,对吗?最终加密的是苹果公司,你不应该在家里尝试这个:)

#include <execinfo.h>
#import <mach-o/ldsyms.h>

bool executableEncryption()
{
    const uint8_t *command = (const uint8_t *) (&_mh_execute_header + 1);
    for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx)
    {
        if (((const struct load_command *) command)->cmd == LC_ENCRYPTION_INFO)
        {
            struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) command;    
            if (crypt_cmd->cryptid < 1)
                return false;
            return true;
        }
        else
        {
            command += ((const struct load_command *) command)->cmdsize;
        }
    }
    return false;
}

【讨论】:

    【解决方案4】:

    苹果官方的回答:

    Hello Dmitry,
    
    Thank you for contacting Apple Developer Technical Support (DTS). 
    
    DTS does not provide code-level support for DRM issues.  
    
    Please try posting your inquiry to Apple Development Forum:
    
    <https://devforums.apple.com>
    
    While you were initially charged a Technical Support Incident (TSI) for this request, we have assigned a replacement TSI back to your account.
    
    Thank you for understanding our support policies.
    
    Best Regards,
    
    Apple Developer Support 
    Worldwide Developer Relations
    

    【讨论】:

    • 你可能更新了你的程序并且没有使用第一个。
    猜你喜欢
    • 1970-01-01
    • 2011-06-13
    • 2011-12-28
    • 2013-12-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多