App Safer iOS 적용 방법

Prev Next

App Safer iOS는 네이버 클라우드 플랫폼이 제공하는 모바일 보안 솔루션으로서, 모바일 기기나 서비스에 위협이 되는 행위를 탐지하는 API를 제공합니다. iOS용 App Safer 라이브러리는 하나의 프레임워크로 구성되어 있으며, Bitcode Enable/Disable 환경을 모두 지원합니다.

App Safer iOS 특징

  • Jailbreak 탐지
  • Simulator 탐지
  • Memory Tampered 탐지
  • Unauthorized Signature 탐지
  • Debugging 탐지
  • Debugging 방지
  • 캡처 방지

App Safer iOS 지원 환경

파일 이름 OS 버전
AppSaferFramework.framework iOS 8.0 이상

App Safer iOS SDK 적용 가이드

AppSaferFramework를 적용하는 방법은 아래와 같습니다.
Xcode 8.0 이상의 환경에서 빌드를 권고합니다.

  1. 다운로드 받은 SDK를 임시 디렉토리에 압축 해제

  2. 프로젝트의Bitcode설정을 확인하고,AppSaferFramework를 프로젝트에 추가

    • Build Settings>Enable Bitcode확인
    • File>Add Files to "Your Project"...>Options>Copy items if needed체크 >AppSaferFramework.framework선택 >Add
  3. (Swift Only)Objective-C호환을 위한Bridging Header생성

    • File>New>File...>Header File> 프로젝트 루트에AppSaferFramework-Bridging-Header.h추가
    • Build Settings>Swift Compiler - General>Objective-C Bridging Header>AppSaferFramework-Bridging-Header.h입력
  • AppSaferFramework-Bridging-Header.h
#ifndef AppSaferFramework_Bridging_Header_h
#define AppSaferFramework_Bridging_Header_h

#import <AppSaferFramework/AppSaferFramework.h>

#endif /* AppSaferFramework_Bridging_Header_h */

디버깅 방지 기능 적용 가이드

디버깅 방지 기능은 App Safer iOS SDK 적용 시 자동으로 적용됩니다.
만약 디버깅이 필요한 경우 App Safer iOS SDK를 일시적으로 적용하지 않은 상태에서 사용하시면 됩니다.

캡처 차단 및 탐지 적용 가이드

App Safer SDK는 캡처 차단 기능으로 앱 미리보기 화면 보호, 스크린샷 탐지, 녹화 및 미러링 시 화면 보호기능을 제공하고 있습니다. 해당 기능을 적용하려면 iOS 13.0 미만에서는 AppDelegate에서 애플리케이션 생명주기에 맞춰 App Safer API 호출이 필요하며, iOS 13.0 이상에서는 SceneDelegate에서 애플리케이션 생명주기에 맞춰 App Safer API 호출이 필요합니다.

차단 및 탐지를 위해 아래 예제 처럼 App Safer API를 호출하시면 캡처 차단 및 탐지 기능이 적용됩니다.
캡처 이벤트 탐지 시 selector를 등록해 callback을 받을 수 있으며, 캡처 이벤트 탐지 시 원하는 동작을 수행할 수 있습니다.

예제

AppDelegate(Swift)
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    @objc func didDetectCapture() -> Void  {
        print("[DETECT] Detected Screenshot in AppDelegate");
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }
}
AppDelegate(Objective-C)
#import "AppDelegate.h"
#import <AppSaferFramework/AppSaferFramework.h>

@interface AppDelegate ()
@end

@implementation AppDelegate

- (void)didDetectCapture {
    NSLog(@"[DETECT] Detected Screenshot in AppDelegate");
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {
    [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
    
    return YES;
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)applicationWillResignActive:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [AppSafer preventScreenshot:_window isInvisible:true];
}
@end
SceneDelegate(Swift)
import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    @objc func didDetectCapture() -> Void  {
        print("[DETECT] Detected Screenshot in AppDelegate");
    }
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
            
            AppSafer.registerScreenProtectionObserver(window, observer: self, selector: #selector(didDetectCapture))
        }
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func sceneWillResignActive(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 0)
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        AppSafer.preventScreenshot(window, isInvisible: 1)
    }
}

SceneDelegate(Objective-C)
#import "SceneDelegate.h"
#import <AppSaferFramework/AppSaferFramework.h>

@interface SceneDelegate ()
@end

@implementation SceneDelegate

- (void)didDetectCapture {
    NSLog(@"[DETECT] Detected Screenshot in SceneDelegate");
}

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)) {
    [AppSafer registerScreenProtectionObserver:_window observer:self selector:@selector(didDetectCapture)];
}

- (void)sceneWillEnterForeground:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)sceneDidBecomeActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:false];
}

- (void)sceneWillResignActive:(UIScene *)scene API_AVAILABLE(ios(13.0)) {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

- (void)sceneDidEnterBackground:(UIScene *)scene API_AVAILABLE(ios(13.0))  {
    [AppSafer preventScreenshot:_window isInvisible:true];
}

@end

App Safer iOS API 목록

  • AppSafer
API 설명
initAppSafer AppSafer을 사용하기 위해 초기화
checkTampering 실시간 보안 탐지
  • Jailbreak 탐지
  • Simulator 탐지
  • Debugging 탐지
  • Memory Tampered 탐지
  • Unauthorized Signature 탐지
setUserId 사용자 ID를 설정
  • AppSaferDelegate
Delegate 필수 설명
appSaferDidInitFinish Required App Safer의 초기화 결과를 전달 받음
appSaferDidCheckTamperingFinish Required checkTampering 함수 수행이 완료되면 결과를 전달
appSaferDetectedJailbreak Optional Jailbreak 탐지 시점에 호출
appSaferDetectedSimulator Optional Simulator 탐지 시점에 호출
appSaferDetectedDebugging Optional Debugging 탐지 시점에 호출
appSaferDetectedMemoryTampered Optional Memory Tampered 탐지 시점에 호출

App Safer iOS API 설명

initAppSafer

App Safer를 사용하기 위해 초기화합니다. 로그를 전송하는 데 필요한 정보 및 전역으로 사용되는 변수를 초기화합니다.

  • App Safer의 모든 API는 initAppSafer()가 성공적으로 호출된 후에 사용할 수 있습니다.
  • 초기화 성공 여부를 전달받기 위해 AppSaferDelegate를 구현해야 합니다.
func initAppSafer(_ delegate: AppSaferDelegate!, serviceCode: String!, key appsaferKey: String!) -> Int32
- (int) initAppSafer:(id<AppSaferDelegate>)delegate serviceCode:(NSString *)serviceCode key:(NSString *)appsaferKey

매개변수

매개변수 설명
delegate AppSaferDelegate가 구현된 인스턴스
serviceCode App Safer 서비스를 이용하기 위한 코드
네이버 클라우드 플랫폼 사용자는 반드시 'ncloud'를 전달
appsaferKey 콘솔에서 앱 등록 시 생성된 appsaferKey값

반환 값

반환 값 설명
SUCCESS(0) 성공
FAIL(-1) 실패

예제

Swift
struct ContentView: View {
    func initAppSaferExample() {
        // APP_SAFER_KEY generated when registering an app to the Console
        let result = AppSafer().initAppSafer(AppSaferDelegator.delegator, serviceCode: "ncloud", key: "<APP_SAFER_KEY>")

        NSLog("initAppSafer() result: %d", result);

        if(result == SUCCESS) {
            // init success
        } else if(result == FAIL) {
            // init fail
        }
    }
    
    var body: some View {
        Button("initAppSafer") {
            initAppSaferExample()
        }
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (IBAction)initAppSaferExample:(id)sender {
    AppSafer *appSafer = [[AppSafer alloc] init];

    int res = FAIL;
    if(appSafer != nil) {
        // APP_SAFER_KEY generated when registering an app to the Console
        res = [appSafer initAppSafer:self serviceCode:@"ncloud" key:@"<APP_SAFER_KEY>"];
        
        NSLog(@"initAppSafer() result: %d", res);

        if(res == SUCCESS) {
            // init success
        }
    }
}

checkTampering

실시간 보안 탐지(Jailbreak 탐지, Simulator 탐지, Debugging 탐지, Memory Tampered 탐지, Unauthorized Signature 탐지)를 수행합니다.
검사 결과를 전달받으려면 AppSaferDelegate를 설정해야 합니다.

func checkTampering()
- (int)checkTampering

반환 값

반환값 설명
SUCCESS(0) 검사 시작 성공
FAIL(-1) 검사 시작 실패
BLOCK(2) 보안 정책을 위반하여 차단
BEFOREINIT(3) App Safer가 초기화되지 않음

예제

Swift
struct ContentView: View {
    func checkTamperingExample() {
        let result = AppSafer().checkTampering()
        
        switch(result) {
        case FAIL:
            print("Failed to check tampering")
            break
        case SUCCESS:
            print("Check Tampering Success")
            break
        case BLOCK:
            print("Device is blocked")
            break
        case BEFOREINIT:
            print("AppSafer is not initialized")
            break
        default:
            break
        }
    }
    
    var body: some View {
        Button("checkTampering") {
            checkTamperingExample()
        }
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (IBAction)checkAppSafer:(id)sender {
    AppSafer *appSafer = [[AppSafer alloc] init];
    
    if(appSafer != nil) {
        int res = [appSafer checkTampering];
        
        switch(res) {
            case FAIL:
                NSLog(@"Failed to check tampering");
                break;
            case SUCCESS:
                NSLog(@"Check Tampering Success");
                break;
            case BLOCK:
                NSLog(@"Device is blocked");
                break;
            case BEFOREINIT:
                NSLog(@"AppSafer is not initialized");
                break;
        }
    } else {
        NSLog(@"AppSafer is nil");
    }
}

@end

setUserId

초기화 및 탐지 이벤트 발생 시 App Safer 서버에 전송되는 로그에 사용자 ID를 포함하고자 할 때 설정합니다.

func setUserId(_ userId: String!) -> Int32
- (int)setUserId:(NSString *)userId

매개변수

매개변수 설명
userId 설정하고자 하는 사용자 식별자

반환 값

반환 값 설명
SUCCESS(0) 설정 성공
FAIL(-1) 설정 실패

예제

Swift
struct ContentView: View {
    func setUserIdExample(_ userId: String) {
        print("setUserId(\(userId))")
        
        let result = AppSafer().setUserId(userId)
        
        switch(result) {
        case FAIL:
            print("Failed to set userId: \(userId)")
            break
        case SUCCESS:
            print("setUserId() Success: \(userId)")
            break
        default:
            break
        }
    }
    
    var body: some View {
        Button("setUserId") {
            setUserIdExample("ExampleUserId")
        }
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (IBAction)setUserId:(id)sender {
    AppSafer *appSafer = [[AppSafer alloc] init];
    
    if(appSafer != nil) {
        NSLog(@"setUserId(%@)", [self.useridText text]);
        
        int res = [appSafer setUserId:[self.useridText text]];

        switch(res) {
            case FAIL:
                NSLog(@"Failed to set userId");
                break;
            case SUCCESS:
                NSLog(@"setUserId Success");
                break;
        }
    } else {
        NSLog(@"AppSafer is nil");
    }
}

App Safer iOS 콜백 함수 설명

App Safer의 검사 함수는 모두 비동기로 동작하며, 결과 처리는 AppSaferDelegate를 통해 위임됩니다.
만약 검사 결과를 받고 싶다면 App Safer에서 제공하는 AppSaferDelegate를 구현하고 initAppSafer() 함수를 이용해 등록해야 합니다.
Swift를 사용할 경우 struct가 아닌 class에 구현해야 하며 AppSaferDelegate와 NSObject를 모두 추가해야 합니다.

appSaferDidInitFinish

initAppSafer() 함수 호출 후 초기화 완료 시 결과를 전달합니다.

func appSaferDidInitFinish(_ result: Int32)
- (void)appSaferDidInitFinish:(int)result

매개변수

매개변수 설명
SUCCESS(0) 초기화 성공
FAIL(-1) 초기화 실패
BLOCK(2) 보안 정책 위반으로 차단 됨

예제

Swift
func appSaferDidInitFinish(_ result: Int32) {
    print("appSaferDidInitFinish result: \(result)");
    if(result == BLOCK) {
        print("Device is blocked!");
        // add to exit application logic
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDidInitFinish:(NSUInteger)result msg:(NSString *)message {
    NSLog(@"appSaferDidInitFinish result: %d", result);
    if(result == BLOCK) {
        NSLog(@"Device is blocked!");
        // add to exit application logic
    }
}

appSaferDidCheckTamperingFinish

checkTampering 함수 호출 후 검사가 완료되면 검사 결과를 전달하기 위해 호출됩니다.

func appSaferDidCheckTamperingFinish(_ result: Int32)
- (void)appSaferDidCheckTamperingFinish:(int)result

매개변수

매개변수 설명
FAIL(-1) 검사 실패
SAFE(0) 이벤트가 탐지되지 않음
DETECT(1) 이벤트 탐지
BLOCK(2) 차단 됨

예제

Swift
func appSaferDidCheckTamperingFinish(_ result: Int32) {
    print("appSaferDidCheckTamperingFinish result: " + (
            result == FAIL   ? "FAIL" :
            result == SAFE   ? "SAFE" :
            result == DETECT ? "DETECT" :
            result == BLOCK  ? "BLOCK": "UNKNOWN"))

    if(result == BLOCK) {
        print("Device is blocked!")
        // add to exit application logic
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDidCheckTamperingFinish:(int)result {
    NSLog(@"appSaferDidCheckTamperingFinish result: %@",
          result == FAIL   ? @"FAIL" :
          result == SAFE   ? @"SAFE" :
          result == DETECT ? @"DETECT" :
          result == BLOCK  ? @"BLOCK": @"UNKNOWN");

    if(result == BLOCK) {
        NSLog(@"Device is blocked!");
        // add to exit application logic
    }
}

appSaferDetectedJailbreak

checkTampering() 함수 호출 후 탈옥이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.

func appSaferDetectedJailbreak()
- (void)appSaferDetectedJailbreak

예제

Swift
func appSaferDetectedJailbreak() {
    print("[DETECT] appSaferDetectedJailbreak");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDetectedJailbreak {
    NSLog(@"[DETECT] appSaferDetectedJailbreak");
}

appSaferDetectedSimulator

checkTampering() 함수 호출 후 가상 머신이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.

func appSaferDetectedSimulator()
- (void)appSaferDetectedSimulator

예제

Swift
func appSaferDetectedSimulator() {
    print("[DETECT] appSaferDetectedSimulator");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDetectedSimulator {
    NSLog(@"[DETECT] appSaferDetectedSimulator");
}

appSaferDetectedDebugging

checkTampering() 함수 호출 후 디버깅이 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.

func appSaferDetectedDebugging()
- (void)appSaferDetectedDebugging

예제

Swift
func appSaferDetectedDebugging() {
    print("[DETECT] appSaferDetectedDebugging");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDetectedDebugging {
    NSLog(@"[DETECT] appSaferDetectedDebugging");
}

appSaferDetectedMemoryTampered

checkTampering() 함수 호출 후 메모리 변조가 탐지되는 시점에 호출됩니다.
checkTampering() 함수 동작이 완료되지 않았더라도 결과를 받고 싶을 때 사용합니다.

func appSaferDetectedMemoryTampered()
- (void)appSaferDetectedMemoryTampered

예제

Swift
func appSaferDetectedMemoryTampered() {
    print("[DETECT] appSaferDetectedMemoryTampered");
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)appSaferDetectedMemoryTampered {
    NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
}

App Safer iOS Use Case

초기화

Swift
import SwiftUI

struct ContentView: View {
    func initAppSaferExample() {
        // APP_SAFER_KEY generated when registering an app to the Console
        let result = AppSafer().initAppSafer(AppSaferDelegator.delegator, serviceCode: "ncloud", key: "<APP_SAFER_KEY>")

        NSLog("initAppSafer() result: %d", result);

        if(result == SUCCESS) {
            // init success
        } else if(result == FAIL) {
            // init fail
        }
    }

    var body: some View {
        Button("initAppSafer") {
            initAppSaferExample()
        }
    }
}

class AppSaferDelegator: NSObject, AppSaferDelegate {
    static let delegator = AppSaferDelegator()
    private override init() {}
    
    func appSaferDidInitFinish(_ result: Int32) {
        print("appSaferDidInitFinish result \(result)");
        if(result == BLOCK) {
            print("Device is blocked!");
            // add to exit application logic
        }
    }
}
Objective-C
#import <AppSaferFramework/AppSaferFramework.h>

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    AppSafer *appSafer = [[AppSafer alloc] init];

    int res = FAIL;
    if(appSafer != nil) {
        // APP_SAFER_KEY generated when registering an app to the Console
        res = [appSafer initAppSafer:self serviceCode:@"ncloud" key:"<APP_SAFER_KEY>"];
        
        NSLog(@"initAppSafer result %d", res);

        if(res == SUCCESS) {
            // init success
        } else if(res == FAIL) {
            // init fail
        }
    } else {
        NSLog(@"AppSafer is nil");
    }
}

- (void)appSaferDidInitFinish:(NSUInteger)result msg:(NSString *)message {
    NSLog(@"appSaferDidInitFinish result %d", result);
    if(result == BLOCK) {
        NSLog(@"Device is blocked!");
        // add to exit application logic
    }
}

실시간 보안 탐지

Swift
import SwiftUI

struct ContentView: View {
    func checkTamperingExample() {
        let result = AppSafer().checkTampering()
        
        switch(result) {
        case FAIL:
            print("Failed to check tampering")
            break
        case SUCCESS:
            print("Check Tampering Success")
            break
        case BLOCK:
            print("Device is blocked")
            break
        case BEFOREINIT:
            print("AppSafer is not initialized")
            break
        default:
            break
        }
    }

    var body: some View {
        Button("checkTampering") {
            checkTamperingExample()
        }
    }
}

class AppSaferDelegator: NSObject, AppSaferDelegate {
    static let delegator = AppSaferDelegator()
    private override init() {}
    
    func appSaferDidCheckTamperingFinish(_ result: Int32) {
        print("appSaferDidCheckTamperingFinish result: " + (
              result == FAIL   ? "FAIL" :
              result == SAFE   ? "SAFE" :
              result == DETECT ? "DETECT" :
              result == BLOCK  ? "BLOCK": "UNKNOWN"))

        if(result == BLOCK) {
            print("Device is blocked!")
            // add to exit application logic
        }
    }

    func appSaferDetectedJailbreak() {
        print("[DETECT] appSaferDetectedJailbreak");
    }
    
    func appSaferDetectedSimulator() {
        print("[DETECT] appSaferDetectedSimulator");
    }

    func appSaferDetectedDebugging() {
        print("[DETECT] appSaferDetectedDebugging");
    }
    
    func appSaferDetectedMemoryTampered() {
        print("[DETECT] appSaferDetectedMemoryTampered");
    }
}
Objective-C
@implementation ViewController

- (IBAction)checkAppSafer:(id)sender {
    AppSafer *appSafer = [[AppSafer alloc] init];
    
    if(appSafer != nil) {
        int res = [appSafer checkTampering];
        
        switch(res) {
            case FAIL:
                NSLog(@"Failed to check tampering");
                break;
            case SUCCESS:
                NSLog(@"Check Tampering Success");
                break;
            case BLOCK:
                NSLog(@"Device is blocked");
                break;
            case BEFOREINIT:
                NSLog(@"AppSafer is not initialized");
                break;
        }
    } else {
        NSLog(@"AppSafer is nil");
    }
}

- (void)appSaferDidCheckTamperingFinish:(int)result {
    if(result == BLOCK) {
        [self.msgbox setText:@"Device is blocked!"];
        // add to exit application
    }

    NSLog(@"appSaferDidCheckTamperingFinish result %@",
          result == FAIL   ? @"FAIL" :
          result == SAFE   ? @"SAFE" :
          result == DETECT ? @"DETECT" :
          result == BLOCK  ? @"BLOCK": @"UNKNOWN");
}

- (void)appSaferDetectedJailbreak {
    NSLog(@"[DETECT] appSaferDetectedJailbreak");
}

- (void)appSaferDetectedSimulator {
    NSLog(@"[DETECT] appSaferDetectedSimulator");
}

- (void)appSaferDetectedDebugging {
    NSLog(@"[DETECT] appSaferDetectedDebugging");
}

- (void)appSaferDetectedMemoryTampered {
    NSLog(@"[DETECT] appSaferDetectedMemoryTampered");
}

참고

본 서비스는 글로벌 리전 서비스로도 제공됩니다.