第一篇:[转]Android逆向之动态调试总结 神乎
[转]Android逆向之动态调试总结
神乎
一、在SO中关键函数上下断点
刚学逆向调试时。大多都满足于在SO中某关键函数上下断点。然后通过操作应用程序,去触发这个断点,然后进行调试
详细的步骤可以参见非虫大大的《Android软件安全与逆向分析》
简单说:在libsyclover.so文件中有一个函数jnicall1。每次单击按钮的时候,便会调用此函数。
1.静态载入此so文件,找到函数的偏移地址为:0x132C2.执行android_server3.端口转发 adb forward tcp:23946 tcp:23946 4.运行程序 5.IDA附加
然后会弹出
点击OK之后,在弹出的列表框中选择需要附加的进程即可 6.下断点
附加完成之后,会停在libc.so这个模块中。此时按下Ctrl + S,弹出模块列表框,搜索so文件名。
记录下基地址:0×76072000(RX权限)
和静态分析时得到的偏移地址0x132C相加得到0x7607332C
G跳转到此位置
F2下好断点!7.触发断点
下好断点,便F9执行,此时状态是runing
此时,去应用中单击按钮,程序便会断在刚刚下好的断点处~
ok~ 这种调试方法局限性很大,适合于比较初级的调试。这种调试手法在现在已经满足不了需求了。
二、在JNI_OnLoad函数上下断点
JNI_OnLoad函数大概功能就是在程序加载so的时候,会执行JNI_OnLoad函数,做一系列的准备工作。
很多时候,程序猿们会将一些重要信息放在此函数中,而不是通过某种事件来重复触发。包括说将反调试函数放置在此函数中。因此,调试手段发生了改变,上述调试方法基本上被淘汰。
1.静态分析,找到JNI_OnLoad函数的偏移:0×1504
2.执行android_server3.端口转发 adb forward tcp:23946 tcp:23946 4.以调试模式启动程序 adb shell am start-D-n com.example.mytestcm/.MainActivity
此时,手机界面会出现Waiting For Debugger页面 5.打开ddms或者Eclipse(必要,为了使用jdb命令)6.IDA附加 7.设置调试选项
Debugger — Debugger Options
8.F9运行程序
IDA中,F9运行程序,此时是runing状态。
在命令行中执行:jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700其中port=8700是从ddms中看到的。
此时程序会断下来 9.下断点
Ctrl + S 然后搜索到so文件名
记录下基地址是:0×76118000
加上JNI_OnLoad函数的偏移地址0×1504为0×76119504
G跳转到0×76119504,下断点
A.触发断点
下好断点之后,直接F9运行吧,就能断在JNI_OnLoad函数处~
当这种调试手法出现之后,将特殊函数,或者反调试函数放在JNI_OnLoad中也不是那么的安全了。此时,程序猿们通过分析系统对SO文件的加载链接过程发现,JNI_OnLoad函数并不是最开始执行的。在JNI_OnLoad函数执行之前,还会执行init段和init_array中的一系列函数。
因此,现在的调试方法,都是将断点下在init_array中~
至于下断点的方法,可以类比于在JNI_OnLoad中下断点的方法,在init_array的函数中下断点。还有一种方法便是通过在linker模块中,通过对其中函数下断点,然后也能单步到init_array中下面便详细介绍下如何给任意系统函数下断点
三、给任意系统函数下断点 1.需要准备的有:
与你调试环境一致的系统源码,这个也可以在http://androidxref.com/网站上在线查阅。
root之后的手机,方便将系统的一些so文件dump至本地,静态获取到系统函数的偏移地址 2.流程
执行android_server
端口转发 adb forward tcp:23946 tcp:23946 调试模式启动程序 adb shell am start-D-n 包名/类名
IDA附加
静态找到目标函数对应所在模块的偏移地址
Ctrl+S找到对应模块的基地址,两个地址相加得到最终地址
G跳转至地址,然后下断
F9运行
执行jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
断下,进行调试
四、在dvmDexFileOpenPartial函数下断点,dump出明文dex 发展至今,从去年到现在,apk的加解密发展非常迅速。国内出现了很多针对apk的加壳保护方案。主要也体现在对dex的保护和对so的保护!针对dex的保护,很长一段时间,都能通过对dvmDexFileOpenPartial函数下断点,从而dump出明文dex文件。
以这次alictf的第三题为例子,展示下如何对dvmDexFileOpenPartial函数下断点!
其他步骤都是一样的,这儿主要说下如何找到dvmDexFileOpenPartial函数位置
1.查看源码
dvmDexFileOpenPartial函数在rewriteDex这个函数中被调用。
可以看到关键字符串信息是:Unable to create DexFile
此时,从手机的/system/lib目录下得到libdvm.so 2.载入IDA,搜索字符串:Unable to create DexFile
得到偏移地址是:0x0005AE8A 3.下断点
搜索模块libdvm.so
基地址是0×41492000
加上偏移地址为0x414ECE8A
G跳转至此位置,下好断点,即可 4.dump明文dex文件
下好断点之后,F9运行,执行jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
程序断下
此时,看到寄存器窗口中的值为:
R0保存dex的起始地址,R1便是dex的长度
直接dump即可!5.后续
dump出来的dex就可以进行反编。
效果如下:
五、写在最后
随着现在技术的发展,对apk的保护是越来越好!大大增加了逆向分析人员的分析难度。同时,在整个攻防的过程中,对攻防两端的人都带来了非常棒体验。双方都取得了长足的进步!
也促使了整个加固方向水平的提升!
其中,动态调试手法在整个过程中是必不可少的。
第二篇:Android之activity总结——转自论坛
Android之activity总结——转自论坛
一、什么是activity Activity 是用户接口程序,原则上它会提供给用户一个交互式的接口功能。它是 android 应用程序的基本功能单元。Activity 本身是没有界面的。所以activity类创建了一个窗口,开发人员可以通过setContentView(View)接口把UI放到activity创建的窗口上,当activity指向全屏窗口时,也可以用其他方式实现:作为漂浮窗口(通过windowIsFloating的主题集合),或者嵌入到其他的activity(使用ActivityGroup)。activity是单独的,用于处理用户操作。几乎所有的activity都要和用户打交道,二、activity生命周期
2011-11-20 20:23:32 上传 下载附件(64.6 KB)由图可知:
在一个Activity正常启动过程中,这些方法调用的顺序是onCreate-> onStart-> onResume;在Activity被kill掉的时候方法顺序是onPause-> onStop-> onDestroy,此为一个完整的Lifecycle。那么对于中断处理(比如电话来了),则是onPause-> onStop,恢复时onStart-> onResume;如果当前应用程序的是一个Theme为Translucent(半透明)或者Dialog 的Activity那么中断就是onPause ,恢复的时候onResume。
那么对于”Other app need memory”,就是我们手机在运行一个应用程序的时候,有可能打进来电话发进来短信,或者没有电了,这时候程序都会被中断,优先去服务电话的基本功能,另外系统也不允许你占用太多资源,至少要保证一些功能(比如电话),所以资源不足的时候也就有可能被kill掉。方法在系统中的作用及我们应该做什么:
onCreate:在这里创建界面,做一些数据的初始化工作;
onStart: 到这一步变成“用户可见不可交互”的状态;
onResume:变成和用户可交互的,(在Activity栈系统通过栈的方式管理这些Activity,即当前Activity在栈的最上端,运行完弹出栈,则回到上一个Activity);
onPause:到这一步是可见但不可交互的,系统会停止动画等消耗CPU的事情。从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降
低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来。
onStop:变得不可见,被下一个activity覆盖了
onDestroy:这是Activity被kill前最后一个被调用方法了,可能是其他类调用finish方法或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判断它,如果你有
一个Progress Dialog在线程中运行,请在onDestroy里把他cancel掉,不然等线程结束的时候,调用Dialog的cancel方法会抛异常。
onPause,onstop,onDestroy,三种状态下 activity都有可能被系统kill 掉。
三、Activity之间的通信
在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
Intent负责对操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
在应用中,我们可以以两种形式来使用Intent:
直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。
间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。对于直接Intent,Android不需要去做解析,因为目标组件已经很明确。
Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。
四、Activity 的 Intent Filter
Intent Filter 描述了一个组件愿意接收什么样的 Intent 对象,Android 将其抽象为 android.content.IntentFilter 类。在 Android 的 AndroidManifest.xml 配置文件中可以通过
当使用 startActivity(intent)来启动另外一个 Activity 时,如果直接指定 intent 对象的 Component 属性,那么 Activity Manager 将试图启动其 Component 属性指定的 Activity。否则 Android 将通过 Intent 的其它属性从安装在系统中的所有 Activity 中查找与之最匹配的一个启动,如果没有找到合适的 Activity,应用程序会得到一个系统抛出的异常。这个匹配的过程如下:
2011-11-20 20:23:59 上传 下载附件(16.72 KB)
五、Activity的栈式管理
Android针对Activity的管理使用的是栈,就是说某一个时刻只有一个Activity处在栈顶,当这个Activity被销毁后,下面的Activity才有可能浮到栈顶,或者有一个新的Activity被创建出来,则旧的Activity就被压栈沉下去了。Activity是Android程序的表现层。程序的每一个显示屏幕就是一个Activity。正在运行的Activity处在栈的最顶端,它是运行状态的。
2011-11-20 20:26:09 上传 下载附件(23.43 KB)
当在程序中调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:它告诉
Activity Manager该Activity实例可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity,把原 Activity 压入到栈的第二层,从 Running 状态转到 Paused 状态。
六、Activity的加载模式standard、singleTop、singleTask、singleInstance(其中前两个是一组、后两个是一组),默认为standard standard:就是intent将发送给新的实例,所以每次跳转都会生成新的activity。singleTop:也是发送新的实例,但不同standard的一点是,在请求的Activity正好位于栈顶时(配置成singleTop的Activity),不会构造新的实例singleTask:和后面的singleInstance都只创建一个实例,当intent到来,需要创建设置为singleTask的Activity的时候,系统会检查栈里面是否已经有该Activity的实例。如果有直接将intent发送给它。singleInstance:首先说明一下task这个概念,Task可以认为是一个栈,可放入多个Activity。比如启动一个应用,那么Android就创建了一个Task,然后启动这个应用的入口Activity,那在它的界面上调用其他的Activity也只是在这个task里面。那如果在多个task中共享一个Activity的话怎么办呢。举个例来说,如果开启一个导游服务类的应用程序,里面有个Activity是开启GOOGLE地图的,当按下home键退回到主菜单又启动GOOGLE地图的应用时,显示的就是刚才的地图,实际上是同一个Activity,实际上这就引入了singleInstance。singleInstance模式就是将该Activity单独放入一个栈中,这样这个栈中只有这一个Activity,不同应用的intent都由这个Activity接收和展示,这样就做到了共享。当然前提是这些应用都没有被销毁,所以刚才是按下的HOME键,如果按下了返回键,则无效。
七、Activity的跳转Activity跳转,无返回结果 这是最简单的Activity跳转方式。从一个Activity启动另一个Activity,直接startActivity(new Intent(当前Activity.this, 下一Activity.class))。
Activity跳转,返回数据/结果 需要返回数据或结果的,则使用startActivityForResult(Intent intent, int requestCode),requestCode的值是自定义的,用于识别跳转的目标Activity。跳转的目标Activity所要做的就是返回数据/结果,setResult(int resultCode)只返回结果不带数据,或者setResult(int resultCode, Intent data)两者都返回!而接收返回的数据/结果的处理函数是onActivityResult(int requestCode, int resultCode, Intent data),这里的requestCode就是startActivityForResult的requestCode,resultCode就是setResult里面的resultCode,返回的数据在data里面。
** 注意,在setResult后,要调用finish()销毁当前的Activity,否则无法返回到原来的Activity,就无法执行原来Activity的onActivityResult函数,看到当前的Activity没反应。