일반적인 제조사(삼성, LG)의 경우에는 adb shell 권한일 경우 접근 가능한 /dev/input/event가 MIUI에서는 개발자 옵션을 활성화 하더라도 기본적으로 사용할 수 없습니다.

 

이는 adb shell(uid 2000)이 관련 권한이 빠져있기 때문이며, 이를 해결하기 위해서는 adb shell 권한으로 제어하기 위해서는 USB 디버깅(보안 설정) 메뉴를 활성화 해야합니다.

 

adb shell을 이용하여 Android에 접속 후 id 명령어를 입력하여 소속된 그룹의 ID(GID)를 확인합니다.

아래의 그림에서 보면 adb shell에 input 그룹(GID 1004)이 미포함 되어있음을 확인할 수 있습니다.

 

 

1) 개발자 옵션 메뉴에 진입 후 USB 디버깅(보안 설정)을 활성화 시도합니다.

 

2) 경고에 대한 1차 설명을 볼 수 있습니다. 5초 대기 후 승인합니다.

 

3) 경고에 대한 2차 설명을 볼 수 있습니다. 5초 대기 후 승인합니다. 

 

4) 마지막 확인창입니다. 5초 대기 후 승인합니다.

 

 

5) 설정 완료

 

USB 디버깅(권한 설정)를 허용 후 조회하면 1004(input) 그룹이 추가되었습니다.

 

이제 adb shell에서 /dev/input/event를 제어할 수 있습니다.

'IT 일반' 카테고리의 다른 글

[MacOS] 컴퓨터이름을 Command로 변경하기  (0) 2023.04.06
Android Screen Mirroring - SCRCPY  (0) 2021.08.04

Byte Stream과 같은 Hex로 구성된 ByteArray Object를 문자열로 변환할 때 한글을 포함한 특수문자를 깨짐 없이 표현하기 위해서는 UTF8로 인코딩해야 합니다.

 

구글에서 검색했을 때 대부분의 사람들은 ASCII로 인코딩하는 예시 코드를 공유해주고 있어서, 3~4시간 정도를 낭비했습니다. ㅠㅠ

정확히 변환되는 코드를 찾아서 기록해두었습니다.

 

아래의 코드 예시를 이용하여 변환하세요.

 

[Code] 

    function UTF8stringFromByteArray(data)
    {
        const extraByteMap = [ 1, 1, 1, 1, 2, 2, 3, 0 ];
        var count = data.length;
        var str = "";
        for (var index = 0;index < count;)
        {
            var ch = data[index++];
            if (ch & 0x80)
            {
                var extra = extraByteMap[(ch >> 3) & 0x07];
                if (!(ch & 0x40) || !extra || ((index + extra) > count))
                    return null;
                ch = ch & (0x3F >> extra);
                for (;extra > 0;extra -= 1)
                {
                    var chx = data[index++];
                    if ((chx & 0xC0) != 0x80)
                        return null;
                    ch = (ch << 6) | (chx & 0x3F);
                }
            }
            str += String.fromCharCode(ch);
        }
        return str;
    }

출처 : https://weblog.rogueamoeba.com/2017/02/27/javascript-correctly-converting-a-byte-array-to-a-utf-8-string/

 

 

 

 

 

조건문 사용시 대괄호 안에 띄어쓰기가 꼭 필요합니다.

 

기본적인 문법

if [[ condition ]]; then
  #statements
elif [[ condition ]]; then
  #statements
else
  #statements
fi

 

첫번째 줄에는 sh 명령어가 있는 위치를 선언해주셔야 합니다.

안드로이드에서 테스트하기 때문에 /system/bin/sh로 지정하였습니다. 

 

예시

#! /system/bin/sh

nowhour=$(date +"%H")
if [[ $nowhour == "12" ]]; then
  echo "지금 시간은 12시에요"
elif [[ $nowhour == "00" ]]; then
  echo "새로운 하루가 시작했어요"
else
  echo "Dinner"
fi

'프로그래밍 > ShellScript' 카테고리의 다른 글

[ IF ] 다중 조건 처리할 때 표현방식  (0) 2023.07.27
디렉터리 존재여부 확인  (0) 2019.04.17

조건문에서 "-d" 옵션을 이용하여 특정 디렉터리가 존재하는지 확인할 수 있습니다.

 

[Code] 

mydir="MyDir"
if [[ -d "$mydir" ]]; then
    echo "Exists"
fi
if [[ ! -d "$mydir" ]]; then
    echo "Not Exists"
fi​

 

 

 

'프로그래밍 > ShellScript' 카테고리의 다른 글

[ IF ] 다중 조건 처리할 때 표현방식  (0) 2023.07.27
[shell script] if  (0) 2019.04.20

1. 목적

본 문서는 Anti-Debugging 기능 중 Attach 선점을 이용한 구현 방법에 대해서 설명합니다.

 

2. 원리

A 프로세스가 B프로세스를 Attach를 먼저 수행하였다면 Detach되기 전까지, C프로세스는 B프로세스를 Attach 할 수 없다.

 

3. Self Attach

 ptrace 함수 호출 시 PTRACE_TRACEME를 전달하여 자기 자신한테 Attach를 적용

A. 필요조건

  • 부모프로세스와 동일한 UID, GID를 가지고 있을 경우
  • 부모프로세스가 CAP_SYS_PTRACE를 가지고 있을 경우

 

B. 예시코드

void anti_debug() {
    long ptrace_status = ptrace(PTRACE_TRACEME, 0, 0, 0);
}

 

C. Android에서 사용불가능한 이유

Android는 zygote가 루트가 아닌 unconfined로 실행되며 CAP_SYS_PTRACE가 설정되어 있습니다.

그래서 Android 4.3까지는 zygote의 하위 프로세스가 Self Attach가 가능했었으나, 

Android 4.4부터는 SELinux가 적용되면서 CAP_SYS_PTRACE 기능이 제한되어 Self Attach를 할 수 없습니다.

 
 

4. Attach from child 

자식프로세스를 생성 후 자식프로세스가 부모프로세스에게 Attach를 적용

A. 필요조건

    부모프로세스가 디버깅 가능한 상태일 경우
    • 앱 Release 빌드의 경우 : 기본값이 Debuggable이 false로 셋팅되므로, ptrace 호출 전 prctl 함수를 이용하여  덤프가능한 상태로 변경 필요.
    • 앱 Debug 빌드의 경우 : 기본값이 Debuggable이 true로 셋팅되므로 추가 작업은 필요없으나, JDWP이 가능한 상태로 권장하지 않음.

B. 예시코드

#include <jni.h>
#include <string>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/wait.h>
#include <android/log.h>
 
 
#define  LOG_TAG    "LEE_NDK"
#define  LOGUNK(...)  __android_log_print(ANDROID_LOG_UNKNOWN,LOG_TAG,__VA_ARGS__)
#define  LOGDEF(...)  __android_log_print(ANDROID_LOG_DEFAULT,LOG_TAG,__VA_ARGS__)
#define  LOGV(...)  __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define  LOGF(...)  __android_log_print(ANDROID_FATAL_ERROR,LOG_TAG,__VA_ARGS__)
#define  LOGS(...)  __android_log_print(ANDROID_SILENT_ERROR,LOG_TAG,__VA_ARGS__)
 
static int child_pid = -2;
static int ptrace_status;
 
//c++11에서는 void *monitor_pid(void *args)
void *monitor_pid(void *) {
    int status;
    waitpid(child_pid, &status, 0);
    /* Child status should never change. */
    _exit(0);
}
 
int anti_debug() {
    if (child_pid == -2) {
        int status_prctl = prctl(PR_SET_DUMPABLE, 1);
        LOGI("status_prctl 상태: %d", status_prctl);
        child_pid = fork();
    }
    if (child_pid == 0) {
        int status;
        pid_t ppid = getppid();
        ptrace_status = ptrace(PTRACE_ATTACH, ppid, 0, 0);
        LOGI("ptrace_status 상태: %d", ptrace_status);
        if (ptrace_status == 0) {
            // 로그 변경 해야함. //
            LOGI("부모프로세스 Attach 성공");
            int waitpid_status = waitpid(ppid, &status, 0);
            LOGI("waitpid : %d", waitpid_status);
            ptrace(PTRACE_CONT, ppid, NULL, NULL);
            while (waitpid(ppid, &status, 0)) {
                if (WIFSTOPPED(status)) {
                    ptrace(PTRACE_CONT, ppid, NULL, NULL);
                } else {
                    LOGI("Ptrace Exit");
                    _exit(0);
                }
            }
        }
        else {
            // ptrace 실패 시 처리 코드 삽입 //
        }
    }
    else {
        pthread_t t;
        pthread_create(&t, NULL, monitor_pid, (void *) NULL);
    }
    if ((child_pid > 0) && (ptrace_status == 0))
        return 0;
    return -1;
}
 
extern "C"
JNIEXPORT void JNICALL Java_kamos_kakao_com_antidebugging_MainActivity_antidebug
        (JNIEnv *env, jobject /* this */) {
    anti_debug();
}
  • 성능 : 디바이스의 성능에 따라 다를 수 있으나, 빠른 응답이 필요한 서비스의 경우 속도 하향이 발생할 수 있음.

 

5. ToDO

  • 다른 프로세스가 선점했을 때 처리 부분 반영 필요
  • 단순히 libc.so에 내장된 ptrace 함수를 사용할 경우 비교적 우호
  • so 파일을 디컴파일 했을 때 쉬운 코드 분석이 가능한 점

 

 

+ Recent posts