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
  • 전체
    오늘
    어제
    • 분류 전체보기 (157)
      • 모의해킹 (18)
      • CTF (22)
      • Wargame (69)
        • Linux_bandit (33)
        • Webhacking.kr (36)
      • DreamHack (52)
        • WEB (14)
        • Reverising (9)
        • System (0)
      • Mobile_security (13)
        • Drozer_Android (4)
        • Frida_Android (1)
        • IOS (1)
        • tool (1)
      • 정보보안기사 (2)
      • IT? (3)
  • 블로그 메뉴

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

    • Github
  • 공지사항

    • DreamHack 에 대한 문제들...
  • 인기 글

  • 태그

    php wrapper
    cookies
    php
    워게임
    drozer
    sql injection
    lfi
    bandit30
    Linux wargame
    webhacking
    리눅스 워게임
    bandit20
    정보보안기사
    OSINT
    wargame
    bandit17
    Android
    webhacking.kr
    Dreamhack
    Linux
    bandit18
    Frida
    insecurebankv2
    bandit
    모의해킹
    url encode
    리눅스
    난독화
    overthewire
    CTF
  • 최근 댓글

  • 최근 글

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

티스토리툴바