Slug conrad cover

iOS 앱을 해킹해보자 : Lyft 앱 리버스 엔지니어링

다른 사람의 코드의 부분이 어떻게 움직이는지 궁금할때나 다른 이의 버그에 시달리는 경우에 소스 코드를 살펴볼 수 있습니다. 단 그 소스코드가 있을 때만 그렇게 할 수 있습니다. Conrad님이 강연에서 소개하는 많은 개념과 도구는 기존 앱의 리버스 엔지니어링뿐만 아니라 다양한 라이브러리와 자신의 코드 디버깅에도 사용할 수 있습니다. 또 코드를 주입하거나 네트워크 트래픽을 조사하여 Lyft iOS 앱을 리버스 엔지니어링 기술도 선보입니다. 이 기술을 사용하면 App Store에 있는 어떤 앱에서도 숨어있는 코드를 발견할 수 있습니다.


소개 (0:00)

저는 Conrad Kramer입니다. Workflow에서 iOS 개발을 하고 있습니다. 지금부터 iOS 앱 리버스 엔지니어링에 대해서 말씀드리고자합니다. 리버스 엔지니어링은 한마디로 최종 결과만을 기준으로 제품을 이해하려고 하는 것입니다. iOS 앱의 맥락에서 App Store에서 다운로드한 .app을 소스코드 없이 앱의 작동 원리를 찾아내는 것을 의미합니다.

리버스 엔지니어링을 할 때 곤란한 점이 두 가지가 있습니다.

  1. 운영체제 도구 는 일반적으로 문서화가 잘 안되어 있고 모호하기 때문에 어렵습니다. 그것은 줄곧 중단되고 아무도 그것을 고칠 사람이 없습니다. 따라서 이러한 도구를 잘 사용할 수 있게 하는 것과 우선 어디서 그것들을 찾아야 하는 지를 아는 것도 어렵습니다.

  2. 이 도구를 사용하더라도 탐색해야할 부분이 많기 때문에 앱에서 무엇을 봐야할지 아는 것이 꽤 힘듭니다. 또한 리버스 엔지니어링을 하는 대상은 앱 뿐인 것은 아닙니다. 폐쇄 소스인 애플의 프레임워크와 같은 것도 리버스 엔지니어링을 할 수 있습니다. UIKit과 다른이의 앱의 버그를 찾을 수 도 있습니다.

그래서 리버스 엔지리어링을 할 때 먼저 할 일은 “이 버그의 원인은 무엇일까? UI 속에서 어떤 구성 요소를 사용하고 있는 걸까?”라고 질문하는 것입니다. 예를 들면, 이 앱이 컬렉션 뷰와 테이블 뷰 중 어느 쪽을 사용하고 있는지를 알고 싶으면 찾을 수 도 있습니다. 그들의 REST API가 어떻게 되어 있는지 알고 싶어지면 그들이 API가 어떻게 동작하는지 실제로 살필 수 있습니다.

Lyft 리버스 엔지니어링 (1:44)

먼저 실험 대상으로 iOS 앱인 Lyft을 사용하기로 결정하였습니다. 이 앱으로 정한 이유는 앱 전체가 Swift로 짜여 있기 때문입니다. 먼저 Swift 애플리케이션 정보를 알고 싶은 것이 무엇인가요? 저는 REST API에 대해 알고 싶고 또는 Web이나 다른 플렛폼에서 자신만의 Lyft 클라이언트를 쓰고싶다고 가정해보겠습니다. API가 어떻게 되어있는지 보고 나면 “URL 체계는 어떻게 작동하는 거지?” 라는 의문이 듭니다. 이건 특히 적절한 질문입니다. 왜냐하면, 여러분이 많은 iOS 앱을 만들고 있고, Lyft에 깊게 접속하고 싶기 때문입니다. 이렇게 하면 특정한 장소와 자동차의 종류를 지정하여 요청하거나 하는 것을 할 수 있습니다. 특히 Workflow에 유용합니다. Workflow 자동화 도구에서 많은 다른 앱을 통합하고 있기 때문입니다. 특히 Lyft의 URL 체계는 아직 공개되지 않았기 때문에 저는 여기에 시간을 쏟겠습니다.

Lyft 엿보기 (2:48)

Lyft 앱 자체는 iTunes에서 다운로드 할 수 있는 .IPA 파일(본질적으로 Zip) 입니다. Info.plist 등의 메타 데이터와 많은 Assets, 이미지, 지역화 문자열등이 포함되어 있습니다. 물론 실행가능한 -흥미로운- 컴파일 된 코드도 포함되어 있습니다. 많은 프레임워크도 포함되어 있습니다. Lyft는 모듈을 권장하는 Swift로 짜여있기 때문에 모듈이 많습니다.

이런 개발 뉴스를 더 만나보세요

Lyft 앱은 완전한 블랙박스입니다. 우리는 실제로 내용을 볼 수 없지만 어떤 각도에 따라서는 들여다 볼 수 있습니다. 우리가 할 수 있는 것 중 하나는 Lyft 앱이 Lyft 서버로 보내는 모든 트래픽을 볼 수 있습니다. 이에 따라 API와 어떻게 상호 작용하는지 뿐만 아니라 서버에 어떤 정보를 보내고 있는지를 살펴 보는 것입니다. 이런 것은 대체로 분석과 비슷하게 피해를 주지 않습니다.

코드를 주입 할 수도 있습니다. 이건 정말 대단하죠. 기본적으로 앱이 움직이고 있을 때 그 살아있는 개체를 찔러볼 수 있습니다. 앱이 실행되지 않는 경우에는 실행 파일인 .app이 어떻게 구성되어 있는지 확인하기 위해 어떤 렌즈를 통해 그 코드를 볼 수 있습니다.

네트워크 트래픽 조사 - Charles 데모 (4:08)

Charles는 트래픽을 인터넷에 보내기 전에 차단하는 HTTPS 프록시 도구입니다. 이것을 사용하여 Lyft 앱에서 나오는 모든 통신을 확인할 수 있습니다.

Lyft는 SSL 트래픽을 암호화 하고 있습니다만 Charles에서 중간자 공격(man-in-the-middle attack)을 하면 쉽게 우회할 수 있습니다. 자체 인증서로 대체하고 나면 iOS 장비에서 신뢰받기 때문에 일반적인 HTTP 통신으로 복호화되어 나타납니다.

Lyft는 앱을 사용하는 동안 서버에 당신 위치 정보를 반복적으로 전송합니다. Charles는 승차 요청 및 취소 요청도 보기 좋게 변환된 JSON 형식으로 표시됩니다. Charles를 사용하면 앱이 인터넷에서 하고 있는 모든 것을 살펴볼 수 있습니다.

앱에 코드를 넣기 - Cycript 데모 (7:44)

정말 멋진 다음 도구는 Cycript입니다. 다른 사람의 앱에 코드를 주입하려면 탈옥이 필요합니다. Cycript는 다른 사람의 코드를 조사할 수 있고 마찬가지로 자신의 앱에서 사용할 수 있습니다. 이것은 Objective-C와 JavaScript의 하이브리드이고 터미널에 Objective-C 코드를 입력하면 앱 내에서 수행 할 수 있습니다. LLDB보다 더 근사한 REPL을 가지고 있습니다. 비록 중단할 수 없고 중단점이나 그와 비슷한 것은 없지만 런타임 코드에 대해 대단한 일을 합니다. 이런식으로 거의 Objective-C와 같은 코드를 넣어봅시다.

var application = [UIApplication sharedApplication];
[application openURL:[NSURL URLWithString:@"https://google.com"]];

탈옥한 iPhone 6에 SSH로 로그인 한 후 Lyft를 시작하고 Cycript를 실행합시다. 그러고 함수 선택을 사용하여 뷰 컨트롤러와 분석 클래스 등의 어떠한 클래스의 인스턴스도 얻을 수 있습니다. 또한 개발자는 특정 API 키에 대한 접근을 방지하기 위해 ACL을 설정해야합니다. 앱이 그것을 얻을 수 있으면, Cycript도 얻을 수 있습니다.

앱의 뷰를 변경할 수도 있습니다. 예를 들어 “Request Ride” 버튼을 녹색으로 바꿔 봅시다. UIApp.keyWindow.recursiveDescription를 사용하여 메모리 주소를 찾아 내고 다음과 같이 입력을 합니다.

var b = new Instance (ADDRESS)
b.backgroundColor = [UIColor greenColor]

Cycript 터미널은 탭 자동완성도 갖추고 있습니다. 이러한 기능은 리버스 엔지니어링하는 것만 아니라 조금 새로운 색상을 시도하는 등 자신의 앱을 간편하게 디버깅하는 데 사용할 수 있습니다.

Q: Cycript를 사용하여 자신의 앱을 디버깅하는 경우에도 디바이스가 탈옥이 되어 있어야 하나요?

Conrad: 자신의 앱이면 탈옥할 필요는 없습니다. 이 도구를 자신의 앱에 포함하는 방법은 cycript.org에 자세하게 나와 있고 지금 데모와 같이 연결하여 디버깅 할 수 있습니다.

실행파일 복호 - dumpdecrypted 데모 (11:28)

다음 앱이 실행되고 있지 않을 때의 실제 코드를 살펴보도록 하겠습니다. 이것은 조금 복잡한 탈옥을 필요로 하지만 조금만 연습하면 쉽게 할 수 있습니다. 우리가 디비아스의 앱들을 재인증 할 수 있기 때문에 애플은 암호화된 앱을 스토어에 올리고 다른 사람과 공유 할 수 없도록 하고 있습니다. 그러나 탈옥이 된 디바이스에서 앱은 복호가 가능합니다. 다른 이들이 dumpdecrypted라고 부르는 것으로 부터 포크하였습니다. 앱을 만든이는 앱을 덤프할 수 있게 하였고 저는 전체 프레임워크를 지원하게 포크하였습니다. 최근에는 모든것이 프레임워크이기 때문에 이 결정은 유용합니다.

사용법은 저장소에서 클론한 후 make하고 탈옥된 아이폰에 앱을 수행하면 됩니다. Lyft에 대해 실행하면 무엇이든지 복호화해줍니다. 전체 파일을 보면 모든 프레임워크에 .decrypted 라는 접미사가 붙어있는 것을 알 수 있습니다. Lyft, LyftKit, LyftSDK에 흥미로운 점은 이들이 SocketRocket, Stripe, Pusher, Mixpanel 등을 사용하고 있다는 점입니다.

실행 파일의 분석 - IDA 데모 (13:47)

덤프를 분 파일을 분석하고 실제 코드를 보려면 이미 친숙할지도 모르는 IDA 라는 도구를 사용합니다. 이 Hopperclass-dump와 비슷한 도구입니다. 앱을 빌드 할 때 Xcode는 실행 파일을 만듭니다. 이것은 어셉블리 코드로 구성이 되어 있습니다. IDA는 실행 파일의 어셈블리를 이쁘게 표시하고 그들을 연결하여 앱의 어셈블리 코드를 그래프로 표시해줍니다. IDA는 비싸지만, 무료버전도 우리가 필요한 기능은 다 있습니다. 그러나 64비트는 지원하지 않습니다.

Lyft가 사용하는 URL 스키마를 찾기 위해 IDA의 검색 바에서 openURL 를 검색해봅시다. Objective-C는 구조의 투명성이 높기 때문에 이 도구와 매우 궁합이 좋습니다. Swift는 조금 까다로워 도구도 아직 별로 대응을 하고 있지 않습니다. Swift 어셈블리는 장황하여 클래스 정보를 추출하는 것은 더 힘듭니다. 하지만 몇번 연습을 하면 결국 어떻게 찾아야 하는지 익히게 됩니다.

IDA 그래프 보기를 사용해보면 _TZFV4Lyft15DeepLinkManager13handleOpenURLfMS0_FCSo5NSURLSb_ 를 찾을 수 있습니다. 이것은 임의의 문자로 되어 있지만 많은 문자 중에서 LyftDeepLinkManager, handleOpenURL 및 NSURL 을 읽을 수 있습니다. 이것은 잘 문서화 되어 있지는 않지만 재밌게도 정의가 충분히 있습니다. Mike Ash의 블로그 Friday Q&A 에서 이러한 임의의 문자에 대해서는 모두 설명이 되어 있습니다. 예를 들어 _T는 Swift의 심볼을 의미하고 F는 함수를 의미, 4Lyft 는 모듈 이름이 되는 등입니다.

Lyft URL 스키마 찾기 (18:23)

우리가 본 것을 기초로 URL 스키마를 결정하기 위해서 개발자 입장에서 생각해야 합니다.

URL 체계는 다음과 같이 구성이 됩니다.

lyft://action?parameter=value

우리는 action이 무엇인지, 취할 수 있는 파라미터의 종류를 찾으려고 노력하고 있습니다. 그리고 딥 링크가 어떻게 작동하는지를 살펴, Swift 프로토콜 DeepLinkAble을 찾았고, 이에 붙어 있는 것은 링크를 나타냅니다. DeepLinkAble를 IDA에서 검색하면 convenient 클래스 클러스터 안에 ride , help , invite , profile등 온갖 요청 개체를 찾을 수 있습니다.

라이드 화면을 여는 방법에 대해서 알고 싶기 때문에 어딘가에 있는 Lyft의 DeepLinkToRide 클래스를 찾아 내 그것이 어떻게 움직이고 있는지 살펴봅시다. 이것을 하기 위해 어셉블리의 지식이 필요하지 않습니다. 필요한 정보에 대한 어셉블리를 검색하여 스캔하는 방법만 알고 있으면 괜찮습니다. 프랑스어를 몰라도 계속 불러를 보고 있으면 결국 그 속에서 뭔가 이해할 수 있는거와 같습니다.IDA를 표시하는 것은 대부분 마치 외국어와 같습니다. Swift에서 리버스 엔지니어링하는 것은 이번이 처음이지만, 그래도 기본적인 점은 알 수 있습니다.

DeepLinkToRide의 그래프를 탐색하면 “pickup”, “[latitude]””, “[longitude]”, “destination” 등의 특정 다른 문자열을 알 수 있을 것입니다. 또한 “ridetype”이라는 것도 있습니다. 여러가지 URL을 사용하여 시도했는데 이것이 action이라는 것을 알 수 있습니다. 또한 “ridetype”을 알아보면서 “lyft”, “lyft_line”, “lyft_plus”, “access”라는 것도 발견했습니다. 이들은 라이드의 종류입니다.

이 다른 URL 부분을 조립하여 여러 요청을 실험한 끝에 승차를 요청하는 방식을 파악했습니다.

lyft://ridetype
      ?id=lyft_line
      &pickup[latitude]=0
      &pickup[longitude]=0
      &destination[latitude]=0
      &destination[longitude]=0

이제 겨우 구조를 알았으므로 Workflow에 통합할 수 있습니다. 이것이 바이너리 분석의 방법입니다. 까다롭고 복잡해보이지만 개발자의 입장에서 생각하면, 일단 해보고 패턴이 일치하는 것을 보는 것은 힘들지 않을 것입니다.

Q&A (22:50)

Q: pinning certificates은 중간자 공격을 방지할 수 있나요?

Conrad: SSL pinning은 중간자 공격을 방지하는 데 사용할 수 있는 테크닉입니다. 이것은 실사용에서 탈옥되지 않는 아이폰을 막기에 좋습니다. 예를 들면 Twitter는 SSL Pinning을 실시하고 있습니다. 그러나 Cycript에서 리버스 엔지니어링은 쉽게 이를 우회할 수 있습니다. 예를 들어 AFNetworking의 SSL Pinning은 SSLPinningMode 라는 속성이 있는데, Cycript를 열고 이를 none 할 뿐입니다. 만약 아이폰이 탈옥이 되어 있으면, 트래픽을 볼 수 있는 것을 방지하는 방법은 없습니다. 만약 탈옥이 되어 있지 않으면 SSL Pinning은 아주 좋은 방어 수단입니다.

Q: cocoapods-keys와 같은 도구를 사용하여 문자열을 난독화하는 것을 추천하시겠습니까?

Conrad: 문자열 난독화는 다음과 같은 것이 유용합니다.

  • Apple의 프레임워크 전용 API를 사용하는 경우는 앱의 검토 과정에서 그것을 감출수 있어 유용합니다. 리뷰어는 자동화된 검사를 하기 때문이죠.

  • 탈옥되지 않는 아이폰을 가지고 있는 사람 또는 난독화를 해제하는 방법을 모르는 사람의 경우 앱의 문자열을 쉽게 찾을 수 없습니다.

하지만 문자열을 영원히 숨길 수 는 없습니다. 예를 들어 Cycript는 swizzle에 의해 난독화를 피할 수 있습니다. 난독화는 보증된 방법은 아니지만 경우에 따라서는 좋은 대항 수단입니다.

Q: class-dumpdumpdecryped와 다른 점은 무엇입니까?

Conrad: 이들은 실제로 다른 도구입니다. dumpdecryped은 App Store의 암포화된 바이너리를 복호하는 것입니다. 그 때 클래스 덤프(class-dumped)는 IDA처럼 암호화되지 않은 바이너리에서 Objective-C 인터페이스 파일을 얻은 것입니다. 불행히도, Swift에 대해선 사용할 수 없습니다.

Q: 이와 같은 Apple의 프레임워크를 공개 GitHub의 라이브러리도 쉽게 클래스 덤프를 할 수 있나요?

Conrad: 네. Apple의 프레임워크는 암호화되어 있지 않기 때문에 쉽게 클래스 덤프 할 수 있습니다. 많은 사람들이 Apple의 개인 인터페이스를 GitHub에 업로드하고 있기 때문에 속을 보면 알 수 있습니다. 매우 편리하네요.

Q: 이 리버스 엔지니어링은 법적으로 문제는 없는 것인가요? Lyft는 그들의 사적인 코드를 훔쳐가는 것에 대해 반대가 있지 않을까요?

Conrad: 법적으로는 너무 엄격하게 따질 필요는 없을 것 같지만 개별 상황에 맞춰 판단할 필요가 있습니다. URL 스키마를 조사하고 있는 것은 파트너에게 이야기하는 것이 좋습니다. 지금까지 우리는 그렇게 하고 있습니다. 예를 들어 최근에 저는 이 문제를 발견하고 Lyft와 상의하고 승인을 받아 그것을 통합할 것입니다. 하지만 개발자가 앱을 부정 행위로부터 보호에 도움이 될 수 있습니다. 예를 들어, 리버스 엔지니어링을 통해 Twitter가 여러분의 장치에 설치되어 있는 앱 목록을 서버에 보내고 있다는 것을 밝혀졌다고 합시다. 좋은 것이든 나쁜것이든 이는 안좋은 영향을 줄 것입니다. 리버스 엔지니어링은 적절하게 사용되어야하고 하나의 도구에 지나지 않습니다.

Q: Apple 프레임워크의 디스 어셉를리하는 과정은 어떻게 됩니까?

Conrad: 이 과정은 내가 한 데모에 있지만 아이폰을 탈옥 할 필요는 없습니다. iTunes는 아이폰을 컴퓨터에 연결한 경우 장치에서 심볼을 보유하고 있습니다. Xcode에서 디렉토리를 찾아 (“device symbols”와 같은 이름으로 되어 있습니다.) Apple의 프레임워크를 IDA와 덤프한 클래스를 열면 분석 할 수 있습니다. 이들은 암호화되지 않기 때문에 사용할 수 있습니다. 이것은 나도 당할 수 밖에 없었지만 베타 iOS의 UIKit 버그를 고치거나 Swizzle라고 패치하는데 굉장히 편리합니다.

번역: Yongbin Cha

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.

Conrad Kramer

Conrad Kramer started developing for iOS after he got involved with the jailbreak scene back in 2010 with his first tweak Graviboard. Since then, he has gotten into regular iOS development and worked on various open source projects in the Cocoa community, like AFOAuth2Client and WFNotificationCenter. Conrad now spends all of his waking hours on Workflow, an automation tool for iOS, where he works on anything from the server backend to building the complex drag and drop interactions.

4 design patterns for a RESTless mobile integration »

close