安卓反调试技术-自带调试检测函数及ptrace检测(3)

原理:

我们进行动态调试的时候,其中有一个步骤是进行jdb连接操作:jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8600,当接连成功之后,isDebuggerConnected() 这个方法就会为ture。

然后我们把三项勾选取消,再点击运行就成功了。

代码 :

这个函数实在Java层的,所以不需要用到.so文件,直接在Mainactivity.java中就可以实现了。

package com.example.myapplicationisdubug;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Debug;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private Thread debuggerCheckThread;    //创建线程也是为了循环检测

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startDebuggerCheckThread();

    }
    private void startDebuggerCheckThread() {
        debuggerCheckThread = new Thread(() -> {
            while (!Thread.interrupted()) {
                // 检查是否有调试器连接
                if (Debug.isDebuggerConnected()) {
                    // 如果有调试器连接,终止进程
                    Log.e("DEBUG", "debugging");    //为了方便得到检测效果
                    android.os.Process.killProcess(android.os.Process.myPid());    //kill进程
                }else{
                    Log.e("DEBUG", "no debug");
                }
                // 每隔1秒检查一次                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // 线程被中断,退出循环
                    break;
                }
            }
        });
        debuggerCheckThread.start();
    }

    protected void onDestroy() {
        super.onDestroy();
        // 确保线程在Activity销毁时被中断
        if (debuggerCheckThread != null) {
            debuggerCheckThread.interrupt();
        }

    }
}

logcat 

adb logcat查看效果,成功!

IDA这边也成功了 

反反调试(待补充):

可以直接修改smali代码或者hook,以后补充

ptrace检测

这是进行的最顺利的一个了。

一个进程同时刻只能被一个进程跟踪,我们可以使用ptrace让进程自己跟踪自己,这样android_server就不能够调试。

代码原型:
#include <sys/ptrace.h>
long ptrace(enum _ptrace_request request,pid_t pid,void* addr,void* data)

效果如下:

当IDA进行附加时,会附加不上,提示这个就表示成功了

同时可以看看这个进程的Tracerpid值,就是zygote的值

使用命令:

ps -ef | grep ptrace

得到该进程的pid值为1662

然后cat /proc/1662/status得到TracerPid的值为128 

再 使用命令ps -ef | grep 128发现就是zygote

反调试代码如下:

MainActivity.java:

package com.example.myapplicationptrace;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

import com.example.myapplicationptrace.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'my_ptrace' library on application startup.
    static {
        System.loadLibrary("my_ptrace");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'myapplicationptrace' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

native-lib.cpp:

#include <jni.h>
#include <string>
#include <linux/ptrace.h>
#include <sys/ptrace.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void ptrace_me(){
    int ch = ptrace(PTRACE_TRACEME,0,NULL,NULL);        //返回-1表示已经被调试
    if (ch == -1){
        int pid = getpid();     //ptrace附加自身,会导致此进程TracerPid变为父进程(zygote)的TracerPid
        kill(pid,SIGKILL);
    }
}


jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    ptrace_me();        //通过JNI_OnLoad方法调用ptrace_me()
    return JNI_VERSION_1_6; // 返回 JNI 版本号
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplicationptrace_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

CMakeLists.txt:

 反反调试:

最简单的也是修改JNI_Onload()的相关方法

就是call这一行

我之前看其他师傅们写的文章,统一是说把相关代码nop掉,但是如果我这里nop掉之后,我返回看IDA的流程图,JNI_Onload()就变得不连续了,所以我其实有怀疑可以是这个原因导致的重新打包签名的apk闪退。

所以我今天没有nop掉代码,而是把call这一行的代码,改成和下面一行mov eax, 10006h一样,这样也不会影响函数逻辑。

然后再重新打包签名,发现成功了,程序也没有闪退! 

注意,重新打包签名之前,需要把META-INF这个文件删了,这个是之前的签名文件

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值