zoukankan      html  css  js  c++  java
  • IDA 静态调试和动态调试

    Fn+f5转成c语言伪代码

    shift+f12 查看文件中所有常量字符串的值

    ctrl+s查看so文件字段信息  

    JNI函数方法名还原 选中v3 按y建 作用(类型还原)


    v3 + 676 前面是一个指针 比如 *(_DWORD *)v3 + 676 表示 v3 是JNIEnv *类型
    形如 *(_DWORD *)vX + YYY 皆是
    可选中v3 按y键进行类型替换,替换为JNIEnv *
    为伪代码添加注释 : /

    g跳转到指定地址

    IDA动态调试

    目的:找到自毁程序的内置密码

    IDA下载配置 mac需要在10.15以下版本才可以使用

    首先,需要准备安卓真机,最好是pxiel 6.0的系统,

    将ida文件夹里面的dbgsrv下的android_server放入真机的/data/local/tmp/下 添加777权限 chmod 777 xxx

     ./android_server运行服务并且监听端口23946 adb forward tcp:23946 tcp:23946

     后面再运行ida 32 点go打开ida new是静态调试

    我们选择 debugger-->attach -remote ARMLinux/Android debugger

     

    输入127.0.0.1点ok。会出来如下界面,如果说链接拒绝,请检查前面启动服务和监听端口是否正常

    我们找到需要调试的进程com.yaotong.crackme点ok

    稍等一会儿之后会出来如下界面

     由于我们之前说过,这个函数的验证密码的函数叫securityCheck

    我们现在需要跳到这个函数的内存地址,去调试这个函数,如何找到这个函数的内存地址呢

    函数运行实际内存地址=头so文件的基地址(根据实际运行情况,此基基地值app每次执行的值都不一样)  + 该函数的偏移量(固定不变.so文件可查看)

    我们现在另外打开一个ida 以静态方法打开此apk的libcrackme.so文件找到securityCheck函数的偏移量为11A8

     再打开以动态方法调试的ida 按control+s(显示app中的so文件)

    我们找到libcrackme.so 找到第一个标有x权限的so文件

    打开

     显示的内存地址为F4395000

     我们打开电脑上的科学计算器,计算方法以16进制进行计算

    用F4395000+11A8得到的就是实际的securityCheck运行的的内存地址 F43961A8

    我们在动态的ida里面按下G 输入刚才得到的内存地址,跳到此内存地址

     跳转后的界面如下

     现在我们对此函数进行调试,我们需要在Java_com_yaotong_crackme_MainActivity_securityCheck函数这里进行打断点调试,右键addbreakpoint

    断点后的样子

     然后我们点左上角点绿色三角形运行按钮,让程序继续运行

    我们再在手机里随便输入个密码比如1111,点击输入密码,让程序进入下一步

    (打上断点以后,程序需要点运行按钮才能继续运行,此时我们才能输入密码,不然程序会一直卡在那里,动不了)

     调试有两个快捷键,F7 和F8   

    F7单步调试,要进入函数
    F8单步调试,不进入函数

    一般都是F8。进入函数步骤太多了。看不出来。我们F8尝试调试

    发现报错,没关系 我们再次尝试

    再次报错,一直都报错,此时 我们想到,可能是此app用了反调试

    IDA调试原理 是利用Linux系统 ptrace 来实现
    当应用被调试时,应用内存里的TracerPid 字段就不为0

    进入设备查看ptrace字段:
    //进入设备
    adb shell
    //获得APP的进程ID

    ps | grep 包名
    //打印该APP里内存状态信息
    cat /proc/pid(进程ID)/status

    TracerPid为 0代表 没有被调试,不为0代表在被调试。
    反调试的原理,检测TracerPid是否被占用,如果被调用。阻止app继续运行

    反反调试
        动态调试,找到检测TracerPid的代码,不执行此代码
    方法:
      此检查代码一般在.init_arra 和 JNI_OnLoad两处。此函数都是在程序最开始运行的时候执行
      在JNI_OnLoad函数出打断点调试,找到检测TracerPid的代码,修改so文件的执行函数,不执行此代码

    IDA调试反调试小经验 如何找到反调试代码:
      结合IDA静态时的代码,观察程序逻辑
      指令一般会整过执行完,直到函数末尾。
    so文件在加载阶段会执行JNI_ONLoad函数。此后便不再执行。要在so文件加载阶段才能给JNI_ONLoad打断点。

    分下面几个步骤:

        1.修改APP的AndroidManifest.xml文件的application字段,再后面加上一段代码android:debuggable=''ture".然后重新打包签名安装

        2.运行的时候检查是否允许debuggable项

    adb shell dumpsys package com.yaotong.crackme(一定要有debuggable 没有的话会导致后面附加进程出现致命错误,无法附加的VM)

     3.以调试模式启动APP,APP此时会挂住

      adb shell am start -D -n 包名/.类名

      adb shell am start -D -n com.yaotong.crackme/.MainActivity(MainActivity是application 下的第一个activity.此activity为初始启动界面)

     挂起 的程序就像上图这样。一直等待调试,

    4.我们打开ida动态调试,对此app再次进行调试

    打开好找到 Debugger-->Debugger options 勾选下图红色选框内容

     再点击一下左上角对运行按钮

     5.再进入设备查看进程对PId ps |grep 包名  或者frida-ps -Ua也可以

       

    6.使JDB命令使程序恢复运行

    adb forward tcp:8700 jdwp:18776(APP的PID)
    jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

    7.so文件在被加载时。ida会停住此文件对加载,我们用control+s来一步步查看libcrackme.so文件是否被加载。并且加载对so文件需要有x权限

    如果未加载。我们再点击左上角对运行按钮,来一步步对尝试,如此反复,直到出现带有x权限对libcrackme.so文件

     点进去,我们得到libcrackme.so文件本次运行的基地址,我们现在需要跳转到JNIONLOAD函数里 对此函数进行调试 G ,然后和JNI_onload内存值相加

     得到这样的图

    现在我们对JNI_onload进行打断点 点左上角的运行三角形,让程序进行运行。F8进行调试

    (对JNI_inload进行调试是找出此段代码中检测tracepid的代码,对检测tracepid的代码进行定位,找到 pthread_create() 的位置。后修改so文件的十六进制内容,从而让此段代码不执行)

    每一步的F8调试,我们都一一都找,鼠标放上去,看到里面运行的代码,找寻 pthread_create这个函数,由于这个函数是一直不停的去检测,应该是个while循环,我们可以按照里面的箭头,线路图,是否有往回走的,来判断pthread_create大致在哪里

     如图 ,找到了 位置在BLX R7位置。现在我们到静态so文件里面 JNI_ONload函数里找到blx r7的执行命令

    鼠标点在blx R7 在点hexview1   阴影的地方就是该函数的运行指令的16进制

     我们现在把37 FF 2E E1复制一下,用文本方式打开so文件,在里面搜索37 FF 2E E1 将搜到的37 FF 2E E1全部改为 00 00 00 00,

    让指令变为空指令

    改完以后报错,再重新打包,签名 安装

    安装完成后,我们就可以重新对securityCheck进行动态调试了

    继续接之前的

    然后我们点左上角点绿色三角形运行按钮,让程序继续运行

    我们再在手机里随便输入个密码比如1111,点击输入密码,让程序进入下一步

    (打上断点以后,程序需要点运行按钮才能继续运行,此时我们才能输入密码,不然程序会一直卡在那里,动不了)

    现在继续调试就不会报错了

    我们一步步的F8向下走。看看程序执行,(在此之前在app上随便输入个密码)

    我们试想这个密码肯定是错的。程序会判断密码是对是错,如果错了,肯定会走错的流程,对了肯定走对的流程,我们一步步的F8,发现

     发现红红色圈子的箭头一直闪,正常应该走短的哪个箭头,结果却绕过短的执行了长的,我们把鼠标放在R0上

    发现寄存器里面的值正好是我们输入的1111 由此可判断这部分函数应该是判断密码和输入的是否正却,我们F5转化为伪代码进行查看

    仔细看这段代码 判断v7不等于v5 break ,v7是v6赋值的。我们把鼠标放在v6上。发现v6的值为aiyou,bucuoo 前面的unsigned __int8可以上网上查下含义,大致的意识是定义类型,

    我们把得到的密码输入进入尝试,发现密码正确,完成

    学自猿人学

  • 相关阅读:
    EBS中的采购单据状态及其控制
    详解EBS接口开发之采购接收&退货处理之关键API--(补充)
    数据挖掘系列
    如果看了这篇文章你还不懂傅里叶变换,那就过来掐死我吧
    机器学习中的数学
    一个机器学习博客 ,包括 Standford公开课machine learning
    机器学习流行算法一览
    java se 另一博客
    java 正则
    java map
  • 原文地址:https://www.cnblogs.com/wuxianyu/p/14276369.html
Copyright © 2011-2022 走看看