0. Android - NDK 학습

2025. 12. 22. 14:01·Mobile_security

0. 학습

모바일 보안, 특히 안드로이드 네이티브 레벨의 보안(리버싱 방지, 취약점 분석, 악성코드 분석 등)을 공부하기 위해서는 NDK는 필수적인 관문이다. 안드로이드 앱의 핵심 로직이나 보안 모듈은 주로 C/C++로 작성되며 '. so'  파일 형태로 존재하기 때문이다.

 

1. NDK 기초와 JNI 메커니즘

먼저 안드로이드 스튜디오 설치 후 

경로: File > Settings (macOS는 Android Studio > Settings) > Languages & Frameworks > Android SDK.

필수 항목 체크

학습에 필요한 필수 항목들을 체크하여 설치 해준다.

 

 

  • NDK (Side by side): 네이티브 코드를 빌드하는 핵심 도구.
  • CMake: 빌드 스크립트를 관리하는 도구.
  • LLDB: 네이티브 코드 전용 디버거 (보안 분석 시 필수) => 최신 안드로이드 스튜디오에서는 이미 깔려있음.

네이티브 코드 : 컴퓨터 프로세서(CPU) 나 운영체제(OS)에서 직접 실행되도록 컴파일된 기계어 형태의 코드

(ex. C, C++ , Swift, Kotlin)

 

 

2. 프로젝트 생성

경로: New Project → Native C++ 선택 → 기본 설정으로 완료.

 

생성을 하면 주요 파일 목록이 뜬다.

 

app/src/main/cpp C/C++ 소스 코드가 위치하는 곳
app/src/main/cpp/CMakeLists.txt 빌드 규칙 파일이다.

어떤 C++파일을 .so 라이브러리로 만들지 정의한다.
app/src/main/java 자바/코틀린 소스 코드 위치이다.

C++ 함수를 호출하는 '입구' 같은 역할
app/build.gradle NDK 버전을 지정하고 CMake와 연결 설정을 하는 곳이다.

 

 

3. JNI (Java Native Interface)

자바(상위 레이어)와 C++(하위 레이어)는 서로 언어가 다르기 때문에 '통역사' 같은 존재가 필요하다 그 규칙이 JNI이다.

=> 안드로이드 앱(Java, Kotlin)과 C++(Native)를 연결하는 통로(Bridge)이다.

 

3-1.MainActivity

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import com.example.myapplication.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Example of a call to a native method
        binding.sampleText.text = stringFromJNI()
    }

    /**
     * A native method that is implemented by the 'myapplication' native library,
     * which is packaged with this application.
     */
    external fun stringFromJNI(): String

    companion object {
        // Used to load the 'myapplication' library on application startup.
        init {
            System.loadLibrary("myapplication")
        }
    }
}

 

3-2.native-lib.cpp => JNI의 실체 

 

  • Java ↔ C++ 연결선
  • 후킹 포인트
  • 보안 로직 진입점
//native-lib.cpp 발췌

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    std::string security_msg = "보안 검사 완료 : " + std::to_string(2025);
    return env->NewStringUTF(hello.c_str());
}

 

 

 

3-3. 라이브러리 로드 : 연결 통로 개방

#CMakeLists.txt 발췌


companion object {
    init {
        System.loadLibrary("myapplication")
    }
}

 

  • JNI 연계: 안드로이드 시스템에 "내가 만든 libmyapplication.so라는 바이너리 파일을 메모리에 올려줘"라고 요청하는 것
  • 보안 포인트: 앱이 실행되자마자 이 코드가 실행함 따라서 보안 설루션은 바로 이 시점에 메모리에 올라오는. so 파일이 변조되었는지 검사하거나, 디버깅 중인지 확인하는 로직을 작동시키곤 한다.

 

3-4. 함수 선언과 이름 규칙 : 주소지 매핑

  • Kotlin (호출자): external fun stringFromJNI(): String
  • C++ (구현자): Java_com_example_myapplication_MainActivity_stringFromJNI
#MainActivity.kt 발췌					  | 		#native-lib.cpp 발췌
external fun stringFromJNI(): String	|  Java_com_example_myapplication_MainActivity_stringFromJNI

 

 

 

만약 소스 코드가 없는 상태에서. so 파일만 가졌을 때 이름만 보고 MainActivity에서  어떤 함수명을 가지는지 확인이 가능하다.

그래서 따로 난독화를 사용한다.

 

3-5. 데이터 타입 변환 : 포장과 해독

C++에서는 std::string 은 자바가 읽지 못하는 구문이다.

따라서 env->NewStringUTF()라는 JNI 함수를 호출하여 자바가 이해할 수 있는 jstring 객체로 변환 한 뒤 넘겨준다.

//native-lib.cpp
    
    std::string hello = "Hello from C++";
    std::string security_msg = "보안 검사 완료 : " + std::to_string(2025);
    return env->NewStringUTF(hello.c_str());

 

 

4. 빌드

Starting Gradle Daemon...
Gradle Daemon started in 10 s 59 ms
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:checkKotlinGradlePluginConfigurationErrors SKIPPED
> Task :app:dataBindingMergeDependencyArtifactsDebug UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:dataBindingGenBaseClassesDebug UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:mapDebugSourceSetPaths UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:compileDebugKotlin UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:compileDebugJavaWithJavac
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeLibDexDebug
> Task :app:mergeDebugJavaResource
> Task :app:dexBuilderDebug
> Task :app:mergeProjectDexDebug
> Task :app:mergeExtDexDebug
> Task :app:configureCMakeDebug[x86_64]
> Task :app:buildCMakeDebug[x86_64]
> Task :app:mergeDebugJniLibFolders
> Task :app:mergeDebugNativeLibs
> Task :app:validateSigningDebug
> Task :app:writeDebugAppMetadata
> Task :app:writeDebugSigningConfigVersions
> Task :app:stripDebugDebugSymbols
> Task :app:packageDebug
> Task :app:createDebugApkListingFileRedirect
> Task :app:assembleDebug

BUILD SUCCESSFUL in 2m 30s
39 actionable tasks: 17 executed, 22 up-to-date

 

빌드 후 결과를 살펴보면

 

> Task :app:configureCMakeDebug[x86_64]
> Task :app:buildCMakeDebug[x86_64]

 

  • CMake 실제로 실행됨
  • Native C++ 코드 컴파일됨
  • x86_64 ABI용. so 생성됨

 

> Task :app:assembleDebug

 

 

  • APK 패키징 완료
  • Debug APK 생성 완료

 

4-1. 빌드 후 apk => zip으로 확장자 변경

apk 파일을 zip으로 변환하여 압축을 푼다.

 

 

4-2.. so 파일 찾기

 

x86_64(에물레이터) 폴더 안에 so 파일이 있는 걸 확인할 수 있다.

ABI 해당 대상
arm64-v8a 스마트폰
armeabi-v7a 오래된 ARM
x86_64 에물레이터
x86 구형 에물레이터

 

'Mobile_security' 카테고리의 다른 글

Android reversing - Plan  (0) 2026.02.03
0. Android - 아키텍처  (0) 2025.12.17
0. Android,IOS - 모바일 사전 지식 정리  (0) 2025.12.11
0. Android - AVD, ADB, Rooting, Pm  (1) 2025.07.22
0. Android Components (글 주의)  (0) 2025.02.01
'Mobile_security' 카테고리의 다른 글
  • Android reversing - Plan
  • 0. Android - 아키텍처
  • 0. Android,IOS - 모바일 사전 지식 정리
  • 0. Android - AVD, ADB, Rooting, Pm
G_OM
G_OM
최대한 설명 열심히 하려고 합니다. 궁금한 거 있으면 언제든지 물어보셔도 좋습니다.
  • G_OM
    끄적끄적
    G_OM
  • 전체
    오늘
    어제
    • 분류 전체보기 (160)
      • 모의해킹 (20)
      • CTF (22)
      • Wargame (69)
        • Linux_bandit (33)
        • Webhacking.kr (36)
      • DreamHack (52)
        • WEB (14)
        • Reverising (9)
        • System (0)
      • Mobile_security (14)
        • Drozer_Android (4)
        • Frida_Android (1)
        • IOS (2)
        • tool (1)
      • 정보보안기사 (2)
      • IT? (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • hELLO· Designed By정상우.v4.10.0
G_OM
0. Android - NDK 학습
상단으로

티스토리툴바