반응형

다음 상태에서 UI Dump수행

 

Frida UI Dump Script

var window = ObjC.classes.UIWindow.keyWindow();
var rootControl = window.rootViewController();

var ui = window.recursiveDescription().toString();
var ui_autolayout = window['- _autolayoutTrace']().toString();
var control = rootControl['- _printHierarchy']().toString();

// 전체 UI 계층 출력하고 싶은 경우    
// console.log("\n\x1b[31m" + ui + "\x1b[0m"); 

// Simplified recursiveDescription
// console.log("\n\x1b[34m" + ui_autolayout + "\x1b[0m");

// 현재 화면에 보여지는 UIController를 알고 싶은 경우
console.log("\n\x1b[32m" + control + "\x1b[0m"); 

==> 실행 결과

 

DVIA_v2.TouchIDDetailsViewController 클래스 추적

Swift Implementation 터치시 -[DVIA_v2.TouchIDDetailsViewController touchIDTapped:] 함수 호출이 일어남

 

IDA에서 -[DVIA_v2.TouchIDDetailsViewController touchIDTapped:] 탐색

 

__T07DVIA_v228TouchIDDetailsViewControllerC13touchIDTappedyypF 으로 따라 들어가면 다음과 같음

LAContext 클래스를 이용하여 TouchID기능을 구현한 것으로 판단됨

 

TouchID기능 구현에는 두가지 접근법이 있는데, 첫번째는 LocalAuthentication.framework에 포함된 LAContext 클래스를 이용하는 것이고, 두번째는 Security.framework 이용하는 것

첫번째 방법의 경우, 적용이 쉽고 빠르지만, 후킹을 통한 인증우회가 가능함

 

LAContext 클래스를 이용한 TouchID기능 구현 Objective-C 예시 코드는 다음과 같음

LAContext *context = [[LAContext alloc] init];  
NSError *error = nil;  
NSString *reason = @"Please authenticate using TouchID.";

if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {  
   [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
       localizedReason:reason
            // reply 메서드에는 block 구문이 인자로 전달되고 있음
           reply:^(BOOL success, NSError *error) {
               if (success) {
                   NSLog(@"Auth was OK");
               } 
               else {
                   //You should do better handling of error here but I'm being lazy
                   NSLog(@"Error received: %d", error);
               }
    }];
} 
else {  
   NSLog(@"Can not evaluate Touch ID");
}

 

reply 메서드의 인자로서 block 구문이 전달되고 있는데, 이것이 frida hooking 포인트.

 

※ block 구문

block은 애플에서 클로저(closure) 개념을 도입하기 위해 만든 문법.("Blocks are closures for C")

다른 언어에서 클로저(closure), 익명함수, 람다함수 또는 일급객체(first-class object)라고 불림

 

다음 IDA Pseudocode를 보면 reply메서드로 넘어가는 인자가 block 구문임을 확인 가능

v28에 _NSConcreteStackBlock(a block located on the stack)을 할당하고, 그 block을 copy하여(_Block_copy() 함수를 사용) heap 영역으로 올린다음, objc_msgSend의 5번째 인자(args[4])로 넘기고 있음

 

-[LAContext evaluatePolicy:localizedReason:reply:] 메서드 호출시 args[4]가 block 구문인지 여부 확인

if(ObjC.available) {
    // LAContext클래스의 evaluatePolicy:localizedReason:reply: 메서드를 이용하여 TouchID기능 구현
    var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
    Interceptor.attach(hook.implementation, {
        onEnter: function(args) {
            // args[4] 인자값이 block 인지 여부 확인
            console.log("\n\x1b[31margs[4]: \x1b[32m" + ObjC.Object(args[4]) + "\x1b[0m");
        },
    });
}

==> 실행 결과

 

Block 구문 hooking 코드를 작성하되, 우선 block구문으로 넘어가는 "success", "error" parameter의 인자값이 무엇인지 관찰

if(ObjC.available) {
    // LAContext클래스의 evaluatePolicy:localizedReason:reply: 메서드를 이용하여 TouchID기능 구현
    var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
    Interceptor.attach(hook.implementation, {
        onEnter: function(args) {
            // args[4] 인자값이 block 인지 여부 확인
            console.log("\n\x1b[31margs[4]: \x1b[32m" + ObjC.Object(args[4]) + "\x1b[0m");
            // block 구문 후킹
            var block = new ObjC.Block(args[4]);
            const appCallback = block.implementation;
            block.implementation = function (success,error)  {
                // block 구문의 인자값 관찰
                console.log("\n\x1b[31msuccess: \x1b[32m" + success  + "\n\x1b[31merror: \x1b[32m" + error + "\x1b[0m");
            };
        },
    });
}

==> 실행 결과

Cancel 버튼 클릭

 

Block 구문의 "success"인자로는 false가 전달되고, "error"인자로는 Error Domain=... 이 전달됨

 

따라서, success인자로 전달되는 값을 true로 변경하고, error인자로 전달되는 값을 null로 변경하면 cancel 버튼을 클릭하여도 인증이 성공할 것으로 판단됨

최종 frida script

if(ObjC.available) {
    // LAContext클래스의 evaluatePolicy:localizedReason:reply: 메서드를 이용하여 TouchID기능 구현
    var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
    Interceptor.attach(hook.implementation, {
        onEnter: function(args) {
            // args[4] 인자값이 block 인지 여부 확인
            console.log("\n\x1b[31margs[4]: \x1b[32m" + ObjC.Object(args[4]) + "\x1b[0m");
            // block 구문 후킹
            var block = new ObjC.Block(args[4]);
            const appCallback = block.implementation;
            block.implementation = function (success,error)  {
                // block 구문의 인자값 관찰
                console.log("\n\x1b[31msuccess: \x1b[32m" + success  + "\n\x1b[31merror: \x1b[32m" + error + "\x1b[0m");
                // block 구문의 반환값 변경
                const result = appCallback(true, null);
                return result;
            };
        },
    });
}

==> 실행 결과

 

※출처

http://highaltitudehacks.com/2018/07/26/ios-application-security-part-50-touch-id-bypass-with-frida/

https://medium.com/@twih1203/objective-c-block-completion-%EA%B5%AC%EB%AC%B8-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-17e08bbc9906

http://seorenn.blogspot.com/2014/04/objective-c-blocks-programming.html

https://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/

http://minsone.github.io/mac/ios/how-to-using-block-in-objc

http://fuckingblocksyntax.com/

https://amattn.com/p/objective_c_blocks_summary_syntax_best_practices.html

반응형

'Information Security > iOS' 카테고리의 다른 글

iOS 13.5.1 탈옥 - Bootrain  (0) 2020.08.17
Frida on Non-Jailbreak Device(Frida 비탈옥단말)  (0) 2020.07.25
DVIA-v2 Jailbreak Detection Test3  (0) 2020.07.14
Cycript(iOS 12.4)  (1) 2020.07.10
DVIA-v2 Jailbreak Detection Test2  (0) 2020.07.10

+ Recent posts