안 드 로 이 드 네 이 티 브 디 버 깅

10913 단어
본문 전재: http://www.zhaoxiaodan.com/java/android/android-native%E5%8F%8D%E8%B0%83%E8%AF%95.html
사고 하 다.
이전에 다른 사람의 암호 화 된 것 을 어떻게 디 버 깅 하고 시도 하 는 지 연 구 했 기 때문에 현재 의 체험 은 다음 과 같다.
사실 중요 한 것 은 당신 이 어떻게 암호 화 하 는 지, 중요 한 것 은 어떻게 다른 사람 에 게 당신 이 어떻게 암호 화 하 는 지 알 리 지 않 는 지 하 는 것 입 니 다.
이러한 프로그램 과 같이 나 는 심지어 네가 어떻게 암호 화 하 는 지 전혀 관심 을 가지 지 않 아 도 된다. 암호 화 알고리즘 이 무엇 인지 나 는 네가 복호화 한 후에 그 자원 의 메모리 블록 이 어디 에 있 는 지, Dumper 를 쓰 면 모두 얻 을 수 있다.
암호 화 는 해 제 를 방지 할 수 없고 해 제 된 난이도 와 문턱 만 증가 할 뿐 암호 화 해 제 는 서로 게임 을 하 는 과정 이다.
자원 을 비밀 로 하면 기술 이 초보 적 이 고 간단하게 복사 하려 는 사람들 에 게 그들 은 너 를 어 쩔 수 없다.그러나 원 리 를 조금 알 고 IDA 를 조금 아 는 사람들 에 게 는 별 쓸모 가 없다.
좋아, 이제 연구 해 볼 게. 어떻게 조금 만 더 문턱 을 늘 릴 수 있 는 지.
이전에 복호화 의 중요 한 전 제 는 바로 디 버 깅 이 었 기 때문에 가장 직접적 으로 생각 하 는 증가 의 문턱 은 바로 이다.
테스트
안 드 로 이 드 프로젝트 를 만 들 고 네 이 티 브 지원 을 추가 합 니 다.
android-anti-debug
먼저 pid 와 부모 pid 를 치고 나 와 보 겠 습 니 다.
#include <jni.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <unistd.h>

#include "log.h"

void anti_debug()
{
    int pid = getpid();
    int ppid = getppid();

    LOGD("pid:%d,ppid:%d",pid,ppid);

}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    anti_debug();
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }

    return JNI_VERSION_1_6;
}
06-11 06:42:24.411: D/[android-anti-debug](1451): pid:1451,ppid:192

pid 192 는:
root      192   1     492204 38400 ffffffff b756598c S zygote

Android 시스템 에서 모든 응용 프로그램 프로 세 스 와 시스템 서비스 프로 세 스 SystemServer 는 Zygote 프로 세 스 가 낳 은 (fork) 것 입 니 다. 이것 을 Zygote (수정란) 라 고 부 르 는 이유 일 수도 있 습 니 다.
구체 적 인 참조: Android 시스템 프로 세 스 Zygote 시작 과정의 소스 코드 분석
보다  /proc/1451/stat
root@mx3:/data/local/tmp # cat /proc/17204//status
Name:   ndroidantidebug
State:  S (sleeping)
Tgid:   17204
Pid:    17204
PPid:   2146
TracerPid:  0
Uid:    10058   10058   10058   10058
Gid:    10058   10058   10058   10058
FDSize: 256
...

gdbserver 로 attach 를 해서 무슨 일이 일 어 났 는 지 보 세 요.
root@mx3:/data/local/tmp # ps |grep blog
u0_a58    30678 2146  907884 59720 ffffffff 4005778c S com.zhaoxiaodan.blog.androidantidebug
root@mx3:/data/local/tmp # ./gdbserver --attach 127.0.0.1:1234 30678
Attached; pid = 30678
Listening on port 1234

root@mx3:/data/local/tmp # cat /proc/17204//status
Name:   ndroidantidebug
State:  t (tracing stop)
Tgid:   17204
Pid:    17204
PPid:   2146
TracerPid: 20337
Uid:    10058   10058   10058   10058
Gid:    10058   10058   10058   10058

발견 TracerPid 줄 이 0 에서 20337 로 바 뀌 었 습 니 다.
ida 이러한 디 버 깅 도 구 는 모두 ptrace 를 사용 하여 진행 되 었 으 며, ptrace 는 매우 중요 한 특정 사항 이 있 습 니 다.
하나의 프로 세 스 는 하나의 프로 세 스 에 의 해 디 버 깅 될 수 밖 에 없다.
그래서 가장 쉬 운 방법 은 JNI_OnLoad 에서 직접 ptrace(PTRACE_TRACEME, 0, 0, 0);방법 1, 직접 ptrace(PTRACE_TRACEME, 0, 0, 0);
#include <jni.h>
#include <stdio.h>
#include <sys/ptrace.h>
#include <unistd.h>

#include "log.h"

void anti_debug()
{
    ptrace(PTRACE_TRACEME, 0, 0, 0);
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    anti_debug();
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }

    return JNI_VERSION_1_6;
}

그리고 gdbserver 로 attach:
root@mx3:/data/local/tmp # ./gdbserver --attach 127.0.0.1:1234 31092
Cannot attach to lwp 31092: Operation not permitted (1)

Exiting

됐어, 끊 을 수가 없어.
그러나 이런 방법 은 역 컴 파일 로 열 면 호출 ptrace 된 곳 을 쉽게 찾 을 수 있 습 니 다. 수정 (예 를 들 어 Nilnil 로 바 꾸 는 것) 을 모 르 고 이 호출 을 건 너 뛰 었 습 니 다.
방법 2, 어두 운 말뚝
위 에서 말 한 /proc/$pid/statusTracerPid 줄 에 디 버 깅 프로그램의 pid 원 리 를 표시 하 는 방법 을 써 서 이 값 을 검사 할 수 있 습 니 다. 만약! =0. 프로그램 종료
검사 함 수 는 다음 과 같 습 니 다:
void be_attached_check()
{
    try
    {
        const int bufsize = 1024;
        char filename[bufsize];
        char line[bufsize];
        int pid = getpid();
        sprintf(filename, "/proc/%d/status", pid);
        FILE* fd = fopen(filename, "r");
        if (fd != nullptr)
        {
            while (fgets(line, bufsize, fd))
            {
                if (strncmp(line, "TracerPid", 9) == 0)
                {
                    int statue = atoi(&line[10]);
                    LOGD("%s", line);
                    if (statue != 0)
                    {
                        LOGD("be attached !! kill %d", pid);
                        fclose(fd);
                        int ret = kill(pid, SIGKILL);
                    }
                    break;
                }
            }
            fclose(fd);
        } else
        {
            LOGD("open %s fail...", filename);
        }
    } catch (...)
    {

    }

}

이 함 수 를 매크로 로 만 든 다음 에 프로그램 을 써 서 랜 덤 으로 이 매크로 를 소스 코드 의 각 곳 에 삽입 할 수 있 습 니 다. 코드 가 계속 실행 되면 서 이러한 검사 점 을 만 날 수 있 습 니 다.
사실 아무런 쓸모 도 없 는데, 단지 말뚝 이 많 을 뿐 이 니, 네가 뽑 으 면 좀 번 거 로 울 것 이다.
다음은 스 레 드 로 검사 과정 을 모 의 하 는 것 입 니 다.
#include "android-anti-debug.h"
#include <string>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdlib.h>
#include <chrono>
#include <thread>
#include "log.h"

void be_attached_check()
{
    try
    {
        const int bufsize = 1024;
        char filename[bufsize];
        char line[bufsize];
        int pid = getpid();
        sprintf(filename, "/proc/%d/status", pid);
        FILE* fd = fopen(filename, "r");
        if (fd != nullptr)
        {
            while (fgets(line, bufsize, fd))
            {
                if (strncmp(line, "TracerPid", 9) == 0)
                {
                    int statue = atoi(&line[10]);
                    LOGD("%s", line);
                    if (statue != 0)
                    {
                        LOGD("be attached !! kill %d", pid);
                        fclose(fd);
                        int ret = kill(pid, SIGKILL);
                    }
                    break;
                }
            }
            fclose(fd);
        } else
        {
            LOGD("open %s fail...", filename);
        }
    } catch (...)
    {

    }

}

//    ,       
void thread_task(int n)
{
    while (true)
    {
        LOGD("start be_attached_check...");
        be_attached_check();
        std::this_thread::sleep_for(std::chrono::seconds(n));
    }
}

void anti_debug()
{
//  ptrace(PTRACE_TRACEME, 0, 0, 0);
    auto checkThread = std::thread(thread_task, 1);
    checkThread.detach();
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    anti_debug();
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }

    return JNI_VERSION_1_6;
}

좋은 웹페이지 즐겨찾기