大家好,又见面了,我是你们的朋友全栈君。
第一、利用IDA静态分析native函数
1.isEquals函数分析 函数指令代码:
简单分析指令代码: 1>、PUSH {r3-r7,lr} 是保存r3,r4,r5,r6,r7,lr 的值到内存的栈中;与之对应的是POP {r3-r7,pc}
pc:程序寄存器,保留下一条CPU即将执行的指令 lr: 连接返回寄存器,保留函数返回后,下一条应执行的指令
2>、调用strlen,malloc,strcpy之前一般都是由MOV指令,用来传递参数值的,比如这里的R5里面存储的就是strlen函数的参数,R0就是is_number函数的参数;在后面的动态调试的过程中可以得到函数的入口参数值。
3>、在每次调用有返回值的函数之后的命令,一般都是比较指令,比如CMP,CBZ,或者是strcmp等,这里是我们激活成功教程的突破点,因为一般加密再怎么厉害,最后比较的参数肯定是正确的密码(或者是正确的加密之后的密码)和我们输入的密码(或者是加密之后的输入密码),我们在这里就可以得到正确密码,或者是加密之后的密码:如上图。
到这里,我们就分析完了native层的密码比较函数:isEquals
2.可以使用F5键,查看他的C语言代码:
看到其实有两个函数是核心点: 1>is_number函数,这个函数我们看名字应该猜到是判断是不是数字,我们可以使用F5键,查看他对应的C语言代码:
主要是看return语句和if判断语句,看到这里有一个循环,然后获取_BYTE*这里地址的值,并且自增加一,然后存到v2中,如果v3为’ ’的话,就结束循环;然后做一次判断,就是v2-48是否大于9,这里我们知道48对应的是ASCII中的数字0,所以这里可以确定的是就是:用一个循环遍历_BYTE*这里存的字符串是否为数字串。
2>get_encrypt_str函数,这个函数我们看到名字可以猜测,他是获取我们输入的密码加密之后的值,再次使用F5快捷键查看:
这里我们看到,首先是一个if语句,用来判断传递的参数是否为NULL,如果是的话,直接返回,不是的话,使用strlen函数获取字符串的长度保存到v2中,然后使用malloc申请一块堆内存,首指针保存到result,大小是v2 1也就是传递进来的字符串长度 1,然后就开始进入循环,首指针result,赋值给i指针,开始循环,v3是通过v1-1获取到的,就是函数传递进来字符串的地址,那么v6就是获取传递进来字符串的字符值,然后减去48,赋值给v7,这里我们可以猜到了,这里想做字符转化,把char转化成int类型,继续往下看,如果v6==48的话,v7=1,也就是说这里如果遇到字符’0’,就赋值1,在往下看,看到我们上面得到的v7值,被用来取key_src数组中的值,那么这里我们双击key_src变量,就跳转到了他的值地方,果不其然,这里保存了一个字符数组,看到他的长度正好是18,那么这里我们应该明白了,这里通过传递进来的字符串,循环遍历字符串,获取字符,然后转化成数字,在倒序获取key_src中的字符,保存到result中。然后返回。
好了,到这里我们就分析完了这两个重要的函数的功能,一个是判断输入的内容是否为数字字符串,一个是通过输入的内容获取密码内容,然后和正确的加密密码:ssBCqpBssP 作比较。
第二、IDA动态调试
这里我们看到没有打印log的函数,所以很难知道具体的参数和寄存器的值,所以这里需要开始调试,得知每个函数执行之后的寄存器的值.
1.IDA配置
获取在IDA安装目录dbgsrvandroid_server: 我们知道(android中的 run-as命令引出升降权限的安全问题(Linux中的setuid和setgid)),如果要调试一个应用进程的话,必须要注入他内部,那么IDA调试so也是这个原理,他需要注入(Attach附加)进程,才能进行调试,但是IDA没有自己弄了一个类似于gdbserver这样的工具,那就是android_server了,所以他需要运行在设备中,保证和PC端的IDA进行通信,比如获取设备的进程信息,具体进程的so内存地址,调试信息等。 所以我们把android_server保存到设备的/data目录下,修改一下他的运行权限,然后必须在root环境下运行,因为他要做注入进程操作,必须要root。
然后我们再看,这里开始监听了设备的23946端口,那么如果要想让IDA和这个android_server进行通信,那么必须让PC端的IDA也连上这个端口,那么这时候就需要借助于adb的一个命令了:
adb forward tcp:远端设备端口号(进行调试程序端) tcp:本地设备端口(被调试程序端)
那么这里,我们就可以把android_server端口转发出去:
然后这时候,我们只要在PC端使用IDA连接上23946这个端口就可以了,这里面有人好奇了,为什么远程端的端口号也是23946,因为后面我们在使用IDA进行连接的时候,发现IDA他把这个端口设置死了,就是23946,所以我们没办法自定义这个端口了。 我们可以使用netstat命令查看端口23946的使用情况,看到是ida在使用这个端口:
2.上面就准备好了android_server,运行成功,下面就来用IDA进行尝试连接,获取信息,进行进程附加注入
我们这时候需要在打开一个IDA,之前打开一个IDA是用来分析so文件的,一般用于静态分析,我们要调试so的话,需要在打开一个IDA来进行,所以这里一般都是需要打开两个IDA,也叫作双开IDA操作。动静结合策略。
这里记得选择go这个选项,就是不需要打开so文件了,进入是一个空白页:
我们选择Debugger选项,选择Attach,看到有很多debugger,所以说IDA工具真的很强大,做到很多debugger的兼容,可以调试很多平台下的程序。这里我们选择Android debugger:
这里看到,端口是写死的:23946,不能进行修改,所以上面的adb forward进行端口转发的时候必须是23946。这里PC本地机就是调试端,所以host就是本机的ip地址:127.0.0.1,点击确定:
这里可以看到设备中所有的进程信息就列举出来的,其实都是android_server干的事,获取设备进程信息传递给IDA进行展示。
双击进程,即可进入调试页面:
这里为什么会断在libc.so中呢? android系统中libc是c层中最基本的函数库,libc中封装了io、文件、socket等基本系统调用。所有上层的调用都需要经过libc封装层。所以libc.so是最基本的,所以会断在这里,而且我们还需要知道一些常用的系统so,比如linker:
还有一个就是libdvm.so文件,他包含了DVM中所有的底层加载dex的一些方法:
我们在后面动态调试需要dump出加密之后的dex文件,就需要调试这个so文件了。
3、找到函数地址,下断点,开始调试
我们使用Ctrl S找到需要调试so的基地址:74FE4000
然后通过另外一个IDA打开so文件,查看函数的相对地址:E9C
那么得到了函数的绝对地址就是:74FE4E9C,使用G键快速跳转到这个绝对地址:
跳转到指定地址之后,开始下断点,点击最左边的绿色圆点即可下断点:
然后点击左上角的绿色按钮,运行,也可以使用F9键运行程序;我们点击程序中的按钮,触发native函数的运行:
看到了,进入调试阶段了,这时候,我们可以使用F8进行单步调试,F7进行单步进入调试:
我们点击F8进行单步调试,达到is_number函数调用出,看到R0是出入的参数值,我们可以查看R0寄存器的内容,然后看到是123456,这个就是Java层传入的密码字符串,接着往下走:
这里把is_number函数返回值保存到R0寄存中,然后调用CBZ指令,判断是否为0,如果为0就跳转到locret_74FE4EEC处,查看R0寄存器的值不是0,继续往下走:
看到了get_encrypt_str函数的调用,函数的返回值保存在R1寄存器中,查看内容:zytyrTRA*B了,那么看到,上层传递的:123456=》zytyrTRA*B了,前面我们静态分析了get_encrypt_str函数的逻辑,继续往下看:
看到了,这里把上面得到的字符串和ssBCqpBssP作比较,那么这里ssBCqpBssP就是正确的加密密码了,那么我们现在的资源是:
正确的加密密码:ssBCqpBssP,加密密钥库:zytyrTRA*BniqCPpVs,加密逻辑get_encrypt_str
那么我们可以写一个逆向的加密方法,去解析正确的加密密码得到值即可,这里为了给大家一个激活成功教程的机会,这里就不公布正确答案了,这个apk我随后会上传,手痒的同学可以尝试激活成功教程一下。
加密apk下载地址:http://download.csdn.net/detail/jiangwei0910410003/9531638
第三、总结激活成功教程流程
到这里,我们就分析了如何激活成功教程apk的流程,下面来总结一下:
1、我们通过解压apk文件,得到对应的so文件,然后使用IDA工具打开so,找到指定的native层函数
2、通过IDA中的一些快捷键:F5,Ctrl S,Y等键来静态分析函数的arm指令,大致了解函数的执行流程
3、再次打开一个IDA来进行调试so
1>将IDA目录中的android_server拷贝到设备的指定目录下,修改android_server的运行权限,用Root身份运行android_server
2>使用adb forward进行端口转发,让远程调试端IDA可以连接到被调试端
3>使用IDA连接上转发的端口,查看设备的所有进程,找到我们需要调试的进程。
4>通过打开so文件,找到需要调试的函数的相对地址,然后在调试页面使用Ctrl S找到so文件的基地址,相加之后得到绝对地址,使用G键,跳转到函数的地址处,下好断点。点击运行或者F9键。
5>触发native层的函数,使用F8和F7进行单步调试,查看关键的寄存器中的值,比如函数的参数,和函数的返回值等信息
总结就是:在调试so的时候,需要双开IDA,动静结合分析。
第四、使用IDA来解决反调试问题
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/191918.html原文链接:https://javaforall.cn