zoukankan      html  css  js  c++  java
  • 【转】andorid ndk anti-debug

    思考

    之前研究了下如何调试和尝试反一个别人加密的东西, 所以现在的体会就是:

    其实重点不是你如何加密, 重点是如何不让别人知道你怎么加密的

    因为像这种自己加密的资源运行的时候自己解密之后拿来用的程序, 我甚至根本不用关心你到底怎么加密, 加密算法是啥, 我只需要知道, 你解密完了之后, 那个资源的内存块在哪, 写个dumper就全拿到了;

    加密并不能防止被破解, 只是增加破解的难度和门槛, 加密解密是一个相互博弈的过程

    把资源加个密, 那么对于那些技术比较初级, 又想简单拷贝的人, 他们就拿你没办法了; 但是对于那些懂一点原理懂一点IDA的人, 并没有什么卵用

    那么好, 现在我要研究一下, 怎么样再增加那么一点点门槛

    之前解密的一个重要前提就是调试, 所以, 最直接想到的增加的门槛就是反调试.

    测试

    先建个android 工程, 并加入native支持

    android-anti-debug

    先打出pid和父pid出来看看

    #include <jni.h>
    #include <stdio.h>
    #include <sys/ptrace.h>
    #include <unistd.h>
    #include "log.h"
    voidanti_debug()
    {
    intpid=getpid();
    intppid=getppid();
    LOGD("pid:%d,ppid:%d",pid,ppid);
    }
    jintJNI_OnLoad(JavaVM*vm,void*reserved)
    {
    anti_debug();
    JNIEnv*env;
    if(vm->GetEnv(reinterpret_cast<void**>(&env),JNI_VERSION_1_6)!=JNI_OK)
    {
    return-1;
    }
    returnJNI_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);

     1  1 #include <jni.h>
     2  2 #include <stdio.h>
     3  3 #include <sys/ptrace.h>
     4  4 #include <unistd.h>
     5  5 #include "log.h"
     6  6 voidanti_debug()
     7  7 {
     8  8 ptrace(PTRACE_TRACEME,0,0,0);
     9  9 }
    10 10 jintJNI_OnLoad(JavaVM*vm,void*reserved)
    11 11 {
    12 12 anti_debug();
    13 13 JNIEnv*env;
    14 14 if(vm->GetEnv(reinterpret_cast<void**>(&env),JNI_VERSION_1_6)!=JNI_OK)
    15 15 {
    16 16 return-1;
    17 17 }
    18 18 returnJNI_VERSION_1_6;
    19 19 }

    然后再用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就退出程序

    检查函数如下:

     1 voidbe_attached_check()
     2 {
     3 try
     4 {
     5 constintbufsize=1024;
     6 charfilename[bufsize];
     7 charline[bufsize];
     8 intpid=getpid();
     9 sprintf(filename,"/proc/%d/status",pid);
    10 FILE*fd=fopen(filename,"r");
    11 if(fd!=nullptr)
    12 {
    13 while(fgets(line,bufsize,fd))
    14 {
    15 if(strncmp(line,"TracerPid",9)==0)
    16 {
    17 intstatue=atoi(&line[10]);
    18 LOGD("%s",line);
    19 if(statue!=0)
    20 {
    21 LOGD("be attached !! kill %d",pid);
    22 fclose(fd);
    23 intret=kill(pid,SIGKILL);
    24 }
    25 break;
    26 }
    27 }
    28 fclose(fd);
    29 }else
    30 {
    31 LOGD("open %s fail...",filename);
    32 }
    33 }catch(...)
    34 {
    35 }
    36 }

    可以把这个函数搞成一个宏, 然后写个程序随机的把这个宏插入到源码的各个地方, 随着代码的不断执行, 会遇到各个这样的检查点

    其实也没什么卵用, 只不过桩子多了, 你拔起来就麻烦点咯

    下面这个只是用线程模拟检查的过程:

     1 #include "android-anti-debug.h"
     2 #include <string>
     3 #include <sys/ptrace.h>
     4 #include <unistd.h>
     5 #include <stdlib.h>
     6 #include <chrono>
     7 #include <thread>
     8 #include "log.h"
     9 voidbe_attached_check()
    10 {
    11 try
    12 {
    13 constintbufsize=1024;
    14 charfilename[bufsize];
    15 charline[bufsize];
    16 intpid=getpid();
    17 sprintf(filename,"/proc/%d/status",pid);
    18 FILE*fd=fopen(filename,"r");
    19 if(fd!=nullptr)
    20 {
    21 while(fgets(line,bufsize,fd))
    22 {
    23 if(strncmp(line,"TracerPid",9)==0)
    24 {
    25 intstatue=atoi(&line[10]);
    26 LOGD("%s",line);
    27 if(statue!=0)
    28 {
    29 LOGD("be attached !! kill %d",pid);
    30 fclose(fd);
    31 intret=kill(pid,SIGKILL);
    32 }
    33 break;
    34 }
    35 }
    36 fclose(fd);
    37 }else
    38 {
    39 LOGD("open %s fail...",filename);
    40 }
    41 }catch(...)
    42 {
    43 }
    44 }
    45 //检查线程, 每秒检查一下
    46 voidthread_task(intn)
    47 {
    48 while(true)
    49 {
    50 LOGD("start be_attached_check...");
    51 be_attached_check();
    52 std::this_thread::sleep_for(std::chrono::seconds(n));
    53 }
    54 }
    55 voidanti_debug()
    56 {
    57 //  ptrace(PTRACE_TRACEME, 0, 0, 0);
    58 autocheckThread=std::thread(thread_task,1);
    59 checkThread.detach();
    60 }
    61 jintJNI_OnLoad(JavaVM*vm,void*reserved)
    62 {
    63 anti_debug();
    64 JNIEnv*env;
    65 if(vm->GetEnv(reinterpret_cast<void**>(&env),JNI_VERSION_1_6)!=JNI_OK)
    66 {
    67 return-1;
    68 }
    69 returnJNI_VERSION_1_6;
    70 }

      

  • 相关阅读:
    1、安装electron
    Bootstrap fileinput v3.0(ssm版)
    Bootstrap fileinput v2.0(ssm版)
    网络概念
    win10远程桌面连接提示身份验证错误,要求的函数不受支持的解决方案
    Quartz 定时任务时间设置
    牛顿迭代法快速寻找平方根
    mysql 中出现:不能打开到主机的连接,在端口3306: 连接失败
    spring boot+mybatis+generator生成domain大小写问题
    Decoder is not a @Sharable handler, so can't be added or removed multiple times
  • 原文地址:https://www.cnblogs.com/dependence/p/4710558.html
Copyright © 2011-2022 走看看