Anroid逆向学习从编写so到静动态调试分析arm的一次总结

一、前言

最近跟着教我兄弟学逆向这篇教程学习Android逆向,在第七课后作业反复折腾了好几天,正好在折腾的时候对前面的学习总结一波,动态分析一下arm汇编(静态看arm感觉跟看天书没什么区别。。。),涉及到的东西都很简单基础,大神就不要浪费时间了!!!


二、所使用到的工具

  • Android studio v3.3
  • IDA v7.0
  • AndroidKiller
  • ApkToolBox v1.6.4

三、编写所需要用到的so和apk文件

关于怎么编写Android应用和so文件,网上一大堆超详细的教程,这里就不再细说了,只简单说一下so文件的编写过程。

1、新建一个java类,使用System.loadLibrary("so_name");来加载so文件,在创建native层函数,我这里创建的一个名为add,形参为两个整数,返回值为一个整数的native函数



2、在Android Studio的终端使用javac java_name.java命令编译刚才添加的类



3、跳转到java目录,生成.h文件,生成命令格式为javah -jni Android项目包名.类名



4、在main文件夹下面新建jni文件夹,然后将上一步在java文件夹下面生成好的.h文件复制到刚新建好的jni文件夹下面,并在相应函数下面编写逻辑代码(我这里比较简单,只实现了两个整数相加并返回结果),然后新建一个util.c的空文件(不加上这个文件会报错。。。)





5、在build.gradle文件中添加相应配置,并且在src目录下建立CMakeLists.txt文件



[代码]

 ndk{
moduleName "myjni"
}
externalNativeBuild{
cmake {
cppFlags ""
abiFilters "arm64-v8a","armeabi-v7a","x86","x86_64"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}

[CMakeLists文件内容]

\# Sets the minimum version of CMake required to build the native
\# library. You should either keep the default value or only pass a
\# value of 3.4.0 or lower. cmake_minimum_required(VERSION 3.4.1) \# Creates and names a library, sets it as either STATIC
\# or SHARED, and provides the relative paths to its source code.
\# You can define multiple libraries, and CMake builds it for you.
\# Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library.AndroidStudio开始支持Cmake了,ndk感觉挺费劲的,这个是不是好玩点,,这里是要生成的库的文件名 libtest.so
\#这里是liuxin
myjni \#so文件名字
\# Sets the library as a shared library.
SHARED \# Provides a relative path to your source file(s).
\# Associated headers in the same location as their source
\# file are automatically included.对应的C文件的目录位置
src/main/jni/main.c) \# Searches for a specified prebuilt library and stores the path as a
\# variable. Because system libraries are included in the search path by
\# default, you only need to specify the name of the public NDK library
\# you want to add. CMake verifies that the library exists before
\# completing its build. find_library( \# Sets the name of the path variable.
log-lib \# Specifies the name of the NDK library that
\# you want CMake to locate.
log ) \# Specifies libraries CMake should link to your target library. You
\# can link multiple libraries, such as libraries you define in the
\# build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library.指定依赖库
\#这里是liuxin
myjni \#so文件名字 \# Links the target library to the log library
\# included in the NDK.关联日志记录库文件,在ndk目录中
${log-lib} )

6、在Build->Rebuild Project编译好so文件,so文件位置存放在build->intermediates->cmake->debug->obj目录下,选取相应的so文件在main的JniLibs目录下(该目录需要自己建立),然后编译好apk即可


四、破解该apk,将结果变为调用该so中该函数时无论参数输入多少,返回结果恒等于0

1、将apk拖进夜神中,观察一波(这里结果为52,参入参数为22和30)



2、将该apk拖进AndroidKiller中反编译,在jd中查看java代码(这里就不再分析smali代码了,直接看java),可以看到在关键函数中调用myTest类的add函数,在jd中双击该类跟进,发现加载了so文件,并且定义了native函数int add(int,int),所以经过上面分析要修改返回值需要修改so文件(也可以在smali层直接修改,但这篇文章主要讲so,如果有兴趣的可以去smali层修改)





3、使用ida静态分析myjni这个so文件。在AndroidKiller中找到该so文件,右键打开文件路径,然后拖进ida中,在export窗口(提供给外界调用的函数名集合的一个窗口)中找到add函数,双击进入该函数,可以看到汇编指令就这两条ADDS R0, R3, R2

BX LR (因为我的函数功能过于简单所以就2条汇编指令,作为学习只有就不要纠结那么多了),第一条意思很简单就是将r3和r2寄存器的值相加复制给r0寄存器,第二条指令意思是跳转到lr寄存器中所指地址中去执行下面的指令(lr是链路寄存器,用于保存函数返回地址,就是相当于存储了函数返回后下一条指令的地址)












4、动态调试。静态其实看着还是挺懵逼的,作为一个arm汇编的初学者,真的是搞不清楚调用函数过程中参数传到那个寄存器中去了,返回值跑哪里去了(暂时只关注这两点),所以那就动态调试so吧(记住一定要用真机调试,反正我用夜神模拟器调试就木有成功过,网上有大佬分析说的是模拟器底层还是x86的汇编,不是arm,所以有各种各样的奇葩错误无法解决)(而且要root)。

(1)、将手机连接好,并进入调试模式,将ida的dbgsrv->android_server拷贝到手机的/data/local/tmp目录下面(打开cmd,输入adb push ida路径/dbgsrv/android_serevr /data/local/tmp拷贝文件至手机),然后输入adb shell进入调试模式下,执行su获取root权限,cd /data/local/tmp进入android_server所在目录下面,chmod 777 android_server赋予android_server文件777(可读可写可执行)权限,./android_server执行android_server文件,最后另外打开一个cmd窗口,执行adb forward tcp:23946 tcp:23946进行端口转发(23946是ida的默认端口,因为木有反调试所以懒得改了)。





(2)、在手机上点击要调试的app启动,然后打开ida,在弹出的初始界面中,选择go这个选项,直接进入ida,然后选择Debugger->Attach->Remote ARMLinux/Android Debugger选项,在弹出的窗口中点击Debug Options选项,勾选下图所示三个选项(这三个选项名字太长了,麻烦看一下图吧),然后点击ok,在点击ok,弹出选择进程的界面,找到要调试的进程(可以使用serarch搜索进程),点击,然后点击ok,然后ida会附加到要调试的进程,在ida右侧的module哪里显示了所有加载的so文件,可以左键点击然后Ctrl+F搜索so文件(我这里so文件名为libmyJni.so,所以我搜索my就行了),找到对应的so文件后,双击即可弹出so文件对应的函数框(我这里是add函数),然后双击对应的函数,ida会跳转到这个函数中去(我这儿就是跳转到了add函数中)。



















3、经过上一步的配置,我们以及成功进入到要调试的函数中了,现在差开始调试了,在ADDS R0, R3, R2处下一个断点(鼠标左键点击这行汇编代码,然后按F2即可下断点),然后按F9运行,在手机上点击按钮,即可看到程序停在了这行代码处,然后按F8单步调试,在右边寄存器处可以看到相关寄存器的16进制值,这里我们可以看到r0寄存器的16进制值为34(10进制为52),可见函数返回结果所用的寄存器为r0,r2寄存器16进制值为16(10进制值为22),对应了我们传进去的第一个参数22,r3寄存器的16进制值为1E(10进制为30),对应了我们传进去的第二个参数30。





4、经过上面的动态分析,我们已经很清楚的知道该函数汇编运行过程--将一个参数值传入寄存器R2,第二个参数值传入寄存器R3,相加结果返回值送入寄存器R0。现在我们需要将结果很等于0,那么我们只需将R0复值为0返回即可。具体思路是将ADDS R0,R2,R3这行汇编代码改为MOV R0,#0即可。现在我们打开ida导入so文件,找到ADDS R0,R2,R3,我们可以点击ida的菜单栏的Options->General,在弹出的窗口中,将bytes改为4,即可显示处汇编指令对应的机器码,现在我们只需要将对应的机器码修改为mov R0,#0对应的机器码即可(可以用ApkToolBox这个工具的arm转机器码这个功能查看汇编对应的机器码)。我们可以使用patch来修改对应的机器码,首先,鼠标左键点击要修改的那行汇编代码,然后我们点击菜单栏的Edit->Patch program->Change bytes,在弹出的窗口修改对应的机器码(因为是Thumb模式,所以修改两个字节即可,这里对应的修改为的机器码为00 20),然后点击菜单栏的Edit->Patch program->Apple patches to input file...即可保存修改。













5、再将得到修改的so文件复制,在AndroidKiller中替换lib目录下所有so文件,然后重新编译即可,在将得到的apk文件安装好即可看到点击按钮显示结果为0。




五、结束语

相关附件链接:链接:https://pan.baidu.com/s/12a_l4JcuJj4i6nJty0xXXQ 提取码:licr 。

Anroid逆向学习从编写so到静动态调试分析arm的一次总结的更多相关文章

  1. CobaltStrike逆向学习系列(12):RDI 任务发布流程分析

    这是[信安成长计划]的第 12 篇文章 0x00 目录 0x01 任务构建 0x02 结果处理 0x03 功能 DLL 分析 之前的分析都是针对整个 CS 的框架来进行的,但是功能也是整个 C2 中相 ...

  2. CobaltStrike逆向学习系列(13):RDI 任务执行流程分析

    这是[信安成长计划]的第 13 篇文章 0x00 目录 0x01 任务号 0x02 功能执行 0x03 结果接收 在上一篇文章中已经讲明了 RDI 类型的任务在发布时候的流程,接下来就是执行了,文中不 ...

  3. CobaltStrike逆向学习系列(8):Beacon 结果回传流程分析

    这是[信安成长计划]的第 8 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 Beacon 接收与处理 0x02 结果回传 Beacon 在接受完命令并执行后,会将数据加密回传给 T ...

  4. CobaltStrike逆向学习系列(7):Controller 任务发布流程分析

    这是[信安成长计划]的第 7 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 Controller->TeamServer 0x02 TeamServer->Beacon ...

  5. CobaltStrike逆向学习系列(2):Stageless Beacon 生成流程分析

    这是[信安成长计划]的第 2 篇文章 关注微信公众号 [信安成长计划] 0x00 目录 0x01 Patch Beacon 0x02 Patch Loader 0x03 文件对比 0x04 流程图 C ...

  6. CobaltStrike逆向学习系列(1):CS 登陆通信流程分析

    这是[信安成长计划]的第 1 篇文章 关注微信公众号[信安成长计划][SecSource] 0x00 目录 0x01 密码校验 0x02 aggressor.authenticate 0x03 agg ...

  7. 【转】安卓逆向实践5——IDA动态调试so源码

    之前的安卓逆向都是在Java层上面的,但是当前大多数App,为了安全或者效率问题,会把一些重要功能放到native层,所以这里通过例子记录一下使用IDA对so文件进行调试的过程并对要点进行总结. 一. ...

  8. android逆向学习小结--CrackMe_1

    断断续续的总算的把android开发和逆向的这两本书看完了,虽然没有java,和android开发的基础,但总体感觉起来还是比较能接收的,毕竟都是触类旁通的.当然要深入的话还需要对这门语言的细节特性和 ...

  9. 从0开始的Python学习013编写一个Python脚本

    通过之前的学习我们已经了解了Python的很多基础运用了,现在我们尝试着做一个有使用价值的小脚本. 问题 需求: 我想要一个可以给我备份重要文件的程序. 需求分析: 首先文件是有存储路径,文件的路径和 ...

随机推荐

  1. 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?

    转载注明:http://dwz.win/gHc 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?".我看网上出现了很多不靠谱的答案.这道题其实很有难度,涉及的知 ...

  2. JS中 isNaN() 方法解析

    1. isNaN() 存在的意义 由于 NaN 是唯一一个不等于自身的值,不像其他的值,可以用相等操作符来判断是否等于自身,NaN == NaN和NaN === NaN都会返回false,所以isNa ...

  3. 存储型XSS的发现经历和一点绕过思路

    再次骚扰 某SRC提现额度竟然最低是两千,而已经有750的我不甘心呐,这不得把这2000拿出来嘛. 之后我就疯狂的挖这个站,偶然发现了一个之前没挖出来的点,还有个存储型XSS! 刚开始来到这个之前挖过 ...

  4. 以后可得记住了--Python笔试面试题小结

    1.字符串处理 将字符串中的数字替换成其两倍的值,例如: 修改前:"AS7G123m (d)F77k" 修改后:"AS14G246m (d)F154k"   个 ...

  5. Nacos整合Spring Cloud Gateway组件

    一.什么是Spring Cloud Gateway Spring Cloud Gateway是Spring Cloud官方推出的网关框架,网关作为流量入口有着非常大的作用,常见的功能有路由转发.权限校 ...

  6. 玩转 SpringBoot 2 快速整合 | 丝袜哥(Swagger)

    概述 首先让我引用 Swagger 官方的介绍: Design is the foundation of your API development. Swagger makes API design ...

  7. Delphi - cxGrid设定合并单元格

    在cxGrid中选中需要合并的字段,单击F11调出属性控制面板,展开Options,设置CellMerging的Value为True.

  8. 一张图了解.Net Core和.NetFx和.Net Standard和Xamarin关系

    一张图了解 .Net Core和.Net Framework和.Net Standard和Xamarin关系 总结 .NET Standard是一项API规范,每一个特定的版本,都定义了必须实现的基类 ...

  9. 爬虫工程师分享:三步就搞定 Android 逆向

    本文源于我近期的一次公司内部分享,通过逆向某款 APP 来介绍逆向过程.由于仅作为学习用途,APP 的相关信息会被遮盖,敬请理解. 关于逆向 逆向--包括但不限于通过反编译.Hook 等手段,来解析一 ...

  10. HDU4348To the moon主席树,区间修改

    题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q l r:查询当前时间戳区间[l,r]中所有数的和 . (3)H l r ...