在android 中,在调试状态下,linux会向/proc/"进程PID"/status 中写入状态信息。其中TracePid 就是调试该进程的进程的的Pid,所以反调试的方法之一就是通过不断轮询检查TracePid的值,假如为0的话,说明该进程没有被调试,假如不为0的话,就说明当前该进程正在被调试,程序执行exit(0)操作。
我直接用一个类来包装我的adb shell:
先通过getpid()函数来查找当前我们程序的pid.然后利用Runtime.getRuntime.exec()函数来执行adb 命令,然后通过BufferReader来读取status 并放入String中。
public final class RootCmd {
public static String GetTracePid(){
int pid =getpid();
String ss=String.valueOf(pid);
Process p = null;
try {
p = Runtime.getRuntime().exec("cat /proc/"+ss+"/status");
} catch (IOException e) {
e.printStackTrace();
}
String data = null;
BufferedReader ie = new BufferedReader(new InputStreamReader(p.getErrorStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String error = null;
try {
while ((error = ie.readLine()) != null
&& !error.equals("null")) {
data += error + "\n";
}
} catch (IOException e) {
e.printStackTrace();
}
String line = null;
try {
while ((line = in.readLine()) != null
&& !line.equals("null")) {
data += line + "\n";
}
} catch (IOException e) {
e.printStackTrace();
}
Log.v("ls", data);
String tmp=data.split("\n")[7];
tmp=tmp.replace("TracerPid:","");
// Log.i("TracePid",tmp);
return tmp;
}
在MainActivity中利用线程不断轮询执行该函数,因为toast只能在主线程中执行,所以利用handleMessage向主线程发送消息。我这里没有用Timer来实现不断轮询执行,我用的是线程的sleep函数
public class MainActivity extends AppCompatActivity {
private Handler handler ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler=new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
Toast toast = Toast.makeText(getApplicationContext(), "程序没有正在被调试", Toast.LENGTH_LONG);
//显示toast信息
//toast 只能在主线程中执行,所以利用handeler message 向主线程发送消息
toast.show();
}
if (msg.what == 1) {
Toast toast = Toast.makeText(getApplicationContext(), "程序正在被调试", Toast.LENGTH_LONG);
//显示toast信息
toast.show();
exit(0);
}
}
};
/* Log.i("SSSSS", "调试开始了");
int pid =getpid();
String ss=String.valueOf(pid);
Log.i("SSSSS",ss);
Toast toast=Toast.makeText(getApplicationContext(),ss, Toast.LENGTH_LONG);
//显示toast信息
toast.show();*/
//利用线程的sleep 定时轮询检查TracePid
new Thread() {
@Override
public void run() {
//这里写入子线程需要做的工作
int flag=1;
while(flag!=0) {
String Tracepid = RootCmd.GetTracePid().trim(); //执行adb命令,查找当前程序是否正在被调试
int Trace = Integer.valueOf(Tracepid).intValue();
if (Trace != 0) {
Log.i("TracePid", "程序正在被调试");
Message message=new Message();
message.what=1;
handler.sendMessage(message);
} else {
Log.i("TracePid", "程序没有正在被调试");
Log.i("TracePid", Tracepid);
Message message=new Message();
message.what=0;
handler.sendMessage(message);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}