React Native 안드로이드 앱(1/2)

Decompile

2018-09-10

React Native는 페이스북에서 공개한 JavaScript와 React를 이용해서 Native 모바일 앱을 만들 수 있도록 하는 라이브러리입니다. 기존의 하이브리드 앱과는 달리 Native 컴포넌트와 매칭된다는 특징이 있습니다. 이번 포스팅에서는 React Native를 이용하여 만들어진 안드로이드 앱을 디컴파일해서 분석해보도록 하겠습니다.

본 포스팅은 react-native, apktool, dex2jar, JD-GUI에 대한 사전 지식이 있다는 가정하에 진행합니다. 관련된 자세한 내용을 알고 싶으신 분은 아래의 링크를 참고하시기 바랍니다.

1
2
3
4
5
6
7
React-native: https://facebook.github.io/react-native/

APKTool: https://ibotpeaches.github.io/Apktool/install/

Dex2jar: https://github.com/pxb1988/dex2jar

JD-GUI: http://jd.benow.ca/

img

먼저 기본적인 React Native 앱을 만들어 보겠습니다.

>react-native init one

위 명령어 입력 후 자동으로 생성되는 파일 중 App.js 파일을 더 간략하게 수정합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, {Component} from 'react'; 
import {StyleSheet, Text, View} from 'react-native';

export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Hello React Native!</Text>
</View>
);
}
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});

수정 후 단말기에 설치하면 다음과 같은 화면이 나타납니다.

img

화면에 “Hello React Native!” 문구가 출력되는 간단한 앱을 만들었습니다. 다음으로 안드로이드 빌드를 하여 apk 파일을 생성해 보겠습니다.

cd android && ./gradlew assembleRelease

위의 명령어를 입력하고 나면 프로젝트 폴더의 하위에 있는 android\app\build\outputs\apk 폴더에 app-release-unsigned.apk 파일이 생성된 것을 확인할 수 있습니다. 이 apk 파일을 dex2jar를 이용하여 코드를 디컴파일하여 확인해 보도록 하겠습니다.

우선 APK 파일을 압축 프로그램을 이용하여 압축을 해제하고 압축 해제한 폴더로 이동합니다.

d2j-dex2jar.sh classes.dex

명령어를 입력한 후 생성된 classes-dex2jar.jar 파일을 JD-GUI 프로그램을 이용하여 열어봅니다.

1
2
3
4
5
6
7
8
package com.one;   
import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {
protected String getMainComponentName() {
return "one";
}
}
MainActivity.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.one;   
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
protected String getJSMainModuleName() {
return "index";
}
protected List<ReactPackage> getPackages() {
return Arrays.asList(new ReactPackage[] { new MainReactPackage() });
}
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
};
public ReactNativeHost getReactNativeHost() {
return this.mReactNativeHost;
}
public void onCreate() {
super.onCreate();
SoLoader.init(this, false);
}
}
MainApplication.class

MainActivity와 MainApplication에는 “Hello React Native!” 를 출력해 주는 앱의 코드가 보이지 않습니다. 이번에는 Apktool을 이용하여 리소스 정보를 확인해보도록 하겠습니다.

java –jar apktool d app-release-unsigned.apk

res\values\strings.xml 파일을 확인해보아도 “Hello React Native!”라는 문구가 보이지 않습니다. React Native 코드는 어디에 있을까요? res\assets\index.android.bundle 파일을 확인해 봅니다.
마지막 라인에,

a.default.createElement(o.Text,{style:c.welcome},"Hello React Native!"))

코드가 확인됩니다.

React Native는 네이티브 컴포넌트로 렌더링되는 자바스크립트 인터페이스를 제공하기 때문에 일반적인 안드로이드 앱을 dex2jar를 이용하여 디컴파일 했을 때와는 차이가 있습니다. 특정 앱이 React Native로 작성이 되었는지를 판단하는 방법은 간단합니다. 디컴파일 후 MainApplication.class에 implements ReactApplication 이 되어 있는지 확인하면 됩니다. 이번에는 “Hello React Native” 문자열을 수정 후 다시 컴파일을 해보도록 하겠습니다.

Index.android.bundle 파일을 열고 “Hello React Native”라는 문자열을 “Hello RN”으로 수정 후 저장합니다. Apktool을 이용하여 리패키징을 하고,

java –jar apktool.jar b app-release-unsigned –o app-release-unsigned-repackage.apk

Keytool을 이용하여 서명키를 생성한 뒤,

keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

Jarsigner를 이용하여 서명을 합니다.

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore app-release-unsigned-repackage.apk alias_name

앱을 설치하면 다음과 같이 문자열이 변경되어 있습니다.

img

React Native로 제작된 앱은 일반적으로 Android Studio와 자바를 이용하여 만들어진 앱을 디컴파일 했을 때와는 차이가 있습니다. 하지만 React Native로 제작된 앱 역시 코드가 bundle 형태의 일반 문자열로 확인 및 수정이 가능합니다. 따라서 중요한 키 정보를 하드코딩 된 텍스트로 보관한다거나 인증을 앱 내부적으로 처리하여 우회 가능한 경로가 발생하지 않도록 앱 개발에 신경 써야 합니다.

React Native를 이용하면 한 번의 개발로 다양한 모바일 플랫폼에 적용할 수 있다는 큰 장점이 있습니다. 하지만 앱 보안은 모바일 플랫폼 별로 적용해야 하는 내용에 차이가 있기 때문에 한 번에 해결하기는 무리가 있습니다. 따라서 React Native로 개발하더라도 각 플랫폼에 대한 공부도 병행해야 할 것입니다.

다음 포스팅에서는 React Native를 이용하여 만든 안드로이드 앱에서의 코드 보호 방법에 대하여 연구해보도록 하겠습니다.


Comments: