阅读更多
一、前言
在之前介绍了很多破解相关的文章,在这个过程中我们难免会遇到一些反调试策略,当时只是简单的介绍了如何去解决反调试,其实在去年我已经介绍了一篇关于Android中的安全逆向防护之战的文章:Android安全逆向防护解析;那么这篇文章就来详细总结一下,现阶段比较流行的几种反调试解决方案。

二、反调试策略方案
第一种:先占坑,自己附加
代码非常简单,在so中加上这行代码即可:ptrace(PTRACE_TRACEME, 0, 0, 0);

其中PTRACE_TRACEME代表:本进程被其父进程所跟踪。其父进程应该希望跟踪子进程,一般一个进程只能被附加一次,我们在破解调试的时候都会附加需要调试应用的进程,如果我们先占坑,父进程附加自己,那么后面在附加调试就会失败。加上这段代码我们运行之后看一下效果:

我们在进行破解动态调试的时候都知道附加进程的status文件中的TracerPid字段就是被调试的进程pid,这里我们运行程序之后,查看进程对应的status文件,发现TracerPid值就是进程的父进程pid值。那么后面如果有进程在想附加调试就是会失败的。这种方式启动一定的调试作用,但是不是绝对安全的。关于解决这种反调试方案后面再说。

第二种:签名校验
其实签名校验,准备来说不算是反调试方案,但是也是一种安全防护策略,就在这里提一下了,而签名校验一般现在有很多用途,用意在于防止二次打包,一般方案有两种:
  • 直接在本地做防护,如果发现签名不一致直接退出应用
  • 将签名信息携带请求参数中参与加密,服务端进行签名校验,失败就返回错误数据即可
而这两种方式也都不是最安全的防护,因为只要有签名校验的逻辑,在本地都可以进行过滤掉。而在之前的好几篇文章中都介绍了如何过滤这种签名校验的方法,不了解的同学可以去查看:Android中破解某应用的签名校验;而对于服务器签名校验以及将签名校验放到so中的文章后面会单独在介绍一篇。

第三种:调试状态检查
这种方式是纯属借助Android中的api进行检验,有两种方法:
第一:检查应用是否属于debug模式
直接调用Android中的flag属性:ApplicationInfo.FLAG_DEBUGGABLE,判断是否属于debug模式:

这个其实就是为了防止现在破解者为了调试应用将应用反编译在AndroidManifest.xml中添加:android:debuggable属性值,将其设置true。然后就可以进行调试。

添加这个属性之后,我们可以用 dumpsys package [packagename] 命令查看debug状态:

所以我们可以检查应用的AppliationInfo的flag字段是否为debuggable即可。不过这种方式也不是万能的,后面会介绍如何解决这种反调试问题。
第二:检查应用是否处于调试状态
这个也是借助系统的一个api来进行判断:android.os.Debug.isDebuggerConnected();这个就是判断当前应用有没有被调试,我们加上这段代码之后,按照之前的那篇文章:脱掉360加固保护壳,其中有一个步骤进行jdb连接操作:

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700,当连接成功之后,这个方法就会返回true,那么我们可以利用这个api来进行判断当前应用是否处于调试状态来进行反调试操作。但是这种方式不是万能的,后面会介绍如何解决这种反调试问题。

第四种:循环检查端口
我们在之前破解逆向的时候,需要借助一个强大利器,那就是IDA,在使用IDA的时候,我们知道需要在设备中启动android_server作为通信,那么这个启动就会默认占用端口23946:

我们可以查看设备的tcp端口使用情况 cat /proc/net/tcp:

其中5D8A转化成十进制就是23946,而看到uid是0,因为我们运行android_server是root身份的,uid肯定是0了。所以我们可以利用端口检查方式来进行反调试策略,当然这种方式不是万能的,后面会详细介绍如何解决这样的反调试方法。

第五种:循环检查TracerPid值
在第一种方式中,我们简单的介绍了如果应用被调试了,那么他的TracerPid值就是调试进程的pid值,而在使用IDA进行调试的时候,需要在设备端启动android_server进行通信,那么被调试的进程就会被附加,这就是android_server进程的pid值了:

查看一下android_server的pid值:

所以我们可以在自己的应用中的native层加上一个循环检查自己status中的TracerPid字段值,如果非0或者是非自己进程pid(如果采用了第一种方案的话,这里也是需要做一次过滤的);那么就认为被附加调试了。当然这里还有一种方案,就是可以检查进程列表中有没有android_server进程,不过这种方式都不是万能的,后面会详细介绍如何解决这种反调试方案。

三、方案策略总结
下面简单几句话总结这几种方案:
第一、自己附加进程,先占坑,ptrace(PTRACE_TRACEME, 0, 0, 0)!
第二、签名校验不可或缺的一个选择,本地校验和服务端校验双管齐下!
第三、借助系统api判断应用调试状态和调试属性,最基础的防护!
第四、轮训检查android_server调试端口信息和进程信息,防护IDA的一种有效方式!
第五、轮训检查自身status中的TracerPid字段值,防止被其他进程附加调试的一种有效方式!

上面就简单的介绍了现在流行的几种应用反调试策略方案,这几种方案可以全部使用,也可以采用几种使用,但是要记住一点,就是如果要做到更安全点,记得把反调试方案放到native层中,时机最早,一般在JNI_OnUnload函数里面,为了更安全点,native中的函数可以自己手动注册,函数名自己混淆一下也是可以的。具体可参见这篇文章:Android安全逆向防护解析。现在一些加固平台为了更有效的防护,启动的多进程之间的防护监听,多进程一起参与反调试方案,这种方式对于破解难度就会增大,但是也不是绝对安全的。文章中对于每种方式最后都说到了,都不是万能安全的,都有方法解决,而这内容放到下一篇来详细介绍了。

反调试方案策略代码下载:https://github.com/fourbrother/android_anti_debug

四、总结
本文主要介绍了Android中应用在进行反调试反破解的几种方案,对于每种方案进行了详细原理分析,代码也给出了下载地址,可以自行运行看效果,而对于这几种反调试方案并非是绝对安全的,后面会再详细介绍如何解决这些反调试功能,但是为了应用安全,这几种方案也不可以不用,有总比没有好!最后读完文章,记得多多点赞分享扩散,要是有打赏就最好啦啦!

更多内容:点击这里
  • 大小: 10.3 KB
  • 大小: 12.8 KB
  • 大小: 19.2 KB
  • 大小: 78 KB
  • 大小: 6.1 KB
  • 大小: 7.4 KB
  • 大小: 4 KB
  • 大小: 5.6 KB
  • 大小: 31.1 KB
  • 大小: 14.3 KB
  • 大小: 96.1 KB
2
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • C# new和override的区别分析

    昨天面试问到了new的几种用法以及与Override的区别,有点模糊 回来google下,new的用法有以下3中 1、运算符:初始化对象和调用构造函数 2、修饰符:隐藏基类方法 3、于在泛型声明中约束可能用作类型参数的参数的类型 至于作为修饰符和override的区别,看了下文章不太明白,写了个例子,运行结果,发现了差异,下面分享下代码:  using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class P

  • C# override和new的区别

    加不加new其实效果一样。加就是为了语意明确。

  • 重写导致的问题

    类中的一个方法,忘记了加override关键字,重写了基类方法,导致调用基类中此方法的按钮,一直执行不到子类的方法。 没有发现这一点时,翻来覆去看代码逻辑,都没有问题呀,后来看到了这个绿色的波浪线,恍然大悟。 看来编译器的警告也不能忽略,就是这种警告: “My.xxx()”将隐藏继承的成员“Base.xxx()”。若要使当前成员重写该实现,请添加关键字 override。否则,添加关键字 n...

  • c# virtual虚函数的new、override实现

    c#中基类(父类)中的某方法若想在派生类(子类)中被重写(override),必须将基类中的方法定义为virtual,即虚函数。若派生类将方法修饰为new,即有意隐藏基类中的方法。 下面看一组代码: public class Father{ public void hand() { Console.WriteLine("Father

  • 关于C#多态的思考

    C# 中,可以如下定义: Base father = new Derived(); father 是基类引用,指向子类对象,这一点有点类似C++。 该引用的使用模式如下(先说结论)—— father引用 可以调用所有 非virtual方法(废话); father 会自动调用子类 override方法(多态); father 无法调用子类新增的方法; 对于子类与父类同名但非over...

  • 覆盖与重载(override/overload) [C#]

    1. 方法签名与方法的显式隐藏     以下程序中,子类B与父类A存在签名相同的函数,将产生方法隐藏。由于没有显式使用new修饰符,编译时出现警告。 签名相同简单的讲是指忽略访问控制符、函数返回值、参数名后其它内容相同。 如:internal int Print(int x)      public void Print(int y)      protected float Print...

  • C#2.0 中 new 和 override 的区别

    如果一个重写的方法没有使用override关键字,编译器会报告一条警告信息:“Console.Application.B.MethodA()”将隐藏继承的成员“ConsoleApplication.A.MethodA()”。若要使当前成员重写该实现,请添加关键字override。否则,请添加关键字new。显然,添加关键字override可以重写父类的方法。还有一个解决方案是关键字new。

  • 运算符重载方法,扩展方法,以及方法参数

    运算符重载方法 一 些编程语言允许定义运算符如果操作类型的实例,例如System.String,System.Decimal,和System.DateTime,它们 重载了==和!=运算符。但是对于CLR来说,它是完全不知道像“==”和“!=”这些运算符是干什么的。编程语言定义了每一种运算符的意义以及当这些运 算符的符号出现时应该生成什么样的代码。例如C#里面,数值类型的当遇到“+”这个符号时,...

  • 引用: 把new、virtual、override说透

    我们先看下面一段程序: ///<summary> ///父类 ///作者:周公 ///首发地址:http://blog.csdn.net/zhoufoxcn/archive/2008/09/02/2864429.aspx ///日期:2008-09-01 ///</summ...

  • 把new、virtual、override说透

    我们先看下面一段程序:    ///      /// 父类 /// 作者:周公 /// 首发地址:http://blog.csdn.net/zhoufoxcn/archive/2008/09/02/2864429.aspx/// 日期:2008-09-01     ///      public class Father    {        pub

  • .Net面试题汇总(一) 帮你轻松过笔试关 --不断增加中

    1、简述 private、 protected、 public、 internal 修饰符的访问权限。 private : 私有成员, 在类的内部才可以访问。protected : 保护成员,该类内部和继承类中可以访问。public : 公共成员,完全公开,没有访问限制。 internal: 当前程序集内可以访问。 2、ADO.NET中的五个主要对象Connection

  • c/c++笔试

    1.进程和线程的差别。线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行(3)拥有资源:进程是拥有资源的独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导

  • 一个男人和三个女人的故事[《.net框架程序设计》_第十一章 多事件示例]

    第十一章 多事件示例[一个男人和三个女人的故事] 摘要:        应用FCL中的System.ComponentModel.EventHandlerList示例一个类型中发布多事件的应用   场景:一个男生有三个女朋友,各自有不同的爱好,女朋友A爱好音乐,女朋友B爱好美食,女朋友C爱好XXX,为满足各个女朋友,此男生必须进行唱歌、烹饪食物、xxx。 以此制作程序演示单类型多事件的应用,并假设

  • [《.net框架程序设计》]第十一章 事件

    第十一章 事件 摘要: ?????? 本章讲述事件的应用,包括: n???????? 发布事件设计模式 n???????? 侦听事件的方法 n???????? 显式控制事件注册 n???????? 一个类型定义多个事件并减少内存资源 ? 一、???????????? 发布事件 1、发布事件的类型提供的功能: l???????? 允许其他对象登记事件 l???????? 允许其他对象注销事件 l??

  • [《.NET框架程序设计》]第八章 常数与字段

    第八章 常数与字段 一、常数 1、可被定义为常数的类型有: 2        基元类型:Boolean, Char, Byte, SByte, Decimal, Int16, Int32, UInt16, UInt32, Int64, UInt64, Single, Double 2        字符串:String 2        枚举类型 2、常数在编译后直接嵌入IL代码中,因此一个模块中

Global site tag (gtag.js) - Google Analytics