吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10697|回复: 16
收起左侧

[Android CTF] 安卓逆向实战题目,ctf 过反调试,以及找到正确密码

[复制链接]
yutao531315 发表于 2020-2-13 22:21
前言:这个apk是在我报名的某个培训班上课的实战题目,感觉挺难的,我也搞了好久,写出来是为了能够增加自己的影响,下次遇到这种类似的有一个分析的方向。
下面我对整个静态分析做一个整理,主要是增强一下我的印象。
刚开始分析这个的时候,胡乱的动态调试,发现啥也找不到,一脸懵逼,最终还是要靠把静态分析啃熟悉了,才能动态调试。不然会给你绕晕,
所以静态分析是特别重要!
先看一下apk文件,  。直接提示密码错误。

1.先对apk进行一个反编译。jadx-gui-0.9.0  打开目标apk,查看安卓配置文件,androidMainifest 配置清单文件找到程序入口界面。

配置文件入口界面.png
看到我指向的一个就是程序的入口界面。直接在class 文件里面找到对应的类目。贴出来代码 关键代码,设置了一个按钮监听,如果点击则直接调用

[Asm] 纯文本查看 复制代码
    public void click(View v) {///设置一个按钮监听事件
        if (this.editText.getText().toString().equals("")) {  //获取输入框的内容,判断是否为空
            Toast.makeText(this, "Please Enter Your PassWord!", 0).show();//为空就弹出,Please Enter Your PassWord
        } else {
            NI.greywolf(this, this.editText.getText().toString());//如果,不为空,则调用ni.greywolf 方法,参数1 this 参数2 我们输入的密码
        }
    }

crlt +点击鼠标查看,这个方法的调用位置,
[Asm] 纯文本查看 复制代码
public class NI {
    public static native void greywolf(Context context, String str); //通过查看greywolf  方法,是一个native修饰的,所以可以断定,这个方法在java层实现,并且是static 静态关键词修饰的。
}


在分析so的时候,一定要吧java层跟so层参数对应关系,对上去才能分析,不然都是白搭, 我也会尽量把我分析的过程写清楚,帮助大家搞懂,我也才能收获更多嘛。
到这里java层就分析完毕了,下面就要进入so层分析,我是用的IDA 7.0
《总结下,在java层,设置一个按钮监听事件,然后调用greywolf  方法,判断输入的注册码是否正确。 》


来到ida ,输出函数界面,ctrl+f    搜索java_ 没有任何结果,那就断定这个apk是采用的JNIload 动态注册

接着在输出函数界面,搜索JNI_ONLoAd  ,

jinload.png

双击进入

[Asm] 纯文本查看 复制代码
ext:00014B58                 PUSH    {R4-R6,LR}      ; JNIload 函数开始位置。
.text:00014B5A                 SUB     SP, SP, #8
.text:00014B5C                 ADD     R5, SP, #0x18+var_14 ; 以上,都是堆栈平衡,做准备工作,我们不分析这段代码
.text:00014B5E                 MOV     R4, R0    此处调用了一个 j_j__Z2ADv  这里面就是apk反调试逻辑,
.text:00014B60                 BL      j_j__Z2ADv      ; 看到一个这段代码,我们进入分析。

直接F5,
看伪代码
为了,验证我们的猜想,我们直接进入 j_j__Z2ADv  

[Asm] 纯文本查看 复制代码
v0 = j_getpid();                              // 获取一个进程pid
  v1 = j_sprintf(&v40, "/proc/%d/status");
  if ( !j_fork(v1) ) 
   //这个就是程序自己fork一个子进程,然后自己附加,让我们ida 没办法附加。

[Asm] 纯文本查看 复制代码
  j_std::basic_ifstream<char,std::char_traits<char>>::~basic_ifstream(&v62);
      if ( !v3 )
      {
        v16 = j_fopen(&v40, "r");
        do
        {
          if ( !j_fgets(&v38, 128, v16) )
            goto LABEL_3;
        }
        while ( j_strncmp(&v38, "TracerPid", 9) );
        v17 = j_atoi(&v39);
        j_fclose(v16);
        if ( !v17 )
        {
LABEL_3:
          j_sleep(1);
          continue;
        }
      }


这里是获取  TracerPid 的值,也是一个反调试逻辑,这里如何过掉反调试,只需要 nop掉这个调用代码处,就过条这个反调试了。



我们来看看完整的汇编代码,
汇编代码.png

这里有一个关键就是注册函数
,程序逻辑我这里一遍

getenv
findclass
第三个是我们重点需要关注的代码。
注册函数逻辑。
[Asm] 纯文本查看 复制代码
.text:00014B92                 MOVS    R0, #0x35C
.text:00014B96                 LDR     R2, [R5]
.text:00014B98                 LDR     R4, [R2,R0]
.text:00014B9A                 LDR     R0, =(_GLOBAL_OFFSET_TABLE_ - 0x14BA0)
.text:00014B9C                 ADD     R0, PC          ; _GLOBAL_OFFSET_TABLE_
.text:00014B9E                 LDR     R2, =(dword_58058 - 0x57678)
.text:00014BA0                 ADDS    R2, R2, R0      ; dword_58058
.text:00014BA2                 MOVS    R3, #1
.text:00014BA4                 MOV     R0, R5
.text:00014BA6                 BLX     R4  


到这里,我们的jniload 函数最关键位置,注册逻辑,
学习过ndk开发的都应该知道, 注册函数一共有四个参数,分别对应的是
1 ENV
2  CLASS
3  注册方法结构体,
4   需要注册函数数量。
这个时候,这几个参数我们理清楚了,下面我们就应该知道,反汇编的参数传递规则
第一个就是,参数 对应的寄存器,按照 R0 R1  R2 R3  顺序
那这时候对应起来的就是
R0 = ENV 上面有个getenv 获取出来的
R1 =CLASS  有个findclass
R2 =方法体 ADDS R2, R2, R0 ; dword_58058
R4 = 注册方法的个数    MOVS R3, #1
{这时候说点题外话,就是那要是有4个以上寄存器我们应该怎么办,就是把多余的参数存放在堆栈里面 然后调用。}、
这里面最关键的就是  方法体了,我们点击
1.png

2
2.png
3

3 3.png
这时候我们就进入了,程序逻辑实现的位置。


F5 查看伪代码。
这时候也到关键位置了,理清楚程序的整个逻辑。
伪代码上。
[Asm] 纯文本查看 复制代码
int (*sub_146A4())()
{
  int (*result)(); // r0

  dword_58058 = j_wolf_de("6C7A5CA7B2DC4B9C");
  dword_5805C = j_wolf_de("234458B0A1C1489300D2572AA3D004E057970FFF6FC1318CF5F6135E6D062813D2642446BD540E79927E12CD4199");
  result = bc;
  dword_58060 = bc;
  return result;
}


看到里面有个bc 方法,我们点击进入


[Asm] 纯文本查看 复制代码
int __fastcall bc(JNIEnv *a1, jclass a2, int a3, String str)//这里就很关键了,参数分别对应,env ,class ,javc层一个参数this,第二个参数,就是我们输入的字符串,这时候我们就要盯着这个str  看看,参数走向是如何走,很容易走偏,
{
  String v4; // r6
  int v5; // r4
  JNIEnv *v6; // r5
  int v7; // r0
  int v8; // r1
  int v10; // r0

  v4 = str;
  v5 = a3;
  v6 = a1;
  v7 = j_jstringTostring(a1, str);///第一个参数 ,env   第二个参数是我们输入的密码。转换一下

  if ( j_dc(v6, v5, v7) )
    return j_jk(v6, v8, v5, v4); //走这里,跟着传入的参数走
  v10 = j_wolf_de("5B694AADB2DC559E44B84637A2D61F");
  return j_st(v6, v5, v10);


*******************************************
[Asm] 纯文本查看 复制代码
int __fastcall jk(int a1, int a2, int a3, int a4)
{
  int v4; // r4
  int v5; // r5
  int v6; // r0
  int result; // r0
  int v8; // r0

  v4 = a3;
  v5 = a1;
  v6 = j_jstringTostring(a1, a4);
  result = j_dc(v5, v4, v6); ///走这里。
  if ( result )
  {
    v8 = j_wolf_de("486757B9B7D2538F089C402CA2CA12AF77D029B071D42787F6A22D502C193A1CCC6C2D49E629");
    result = j_st(v5, v4, v8);
  }
  return result;
}

到这里。

[Asm] 纯文本查看 复制代码
int __fastcall dc(int a1, int a2, int a3)
{
  int v3; // r4
  int v4; // r5
  int v5; // r6
  int v6; // r1
  int result; // r0

  v3 = a3;
  v4 = a2;
  v5 = a1;
  v6 = j_dh(a1, a2);
  result = 0;
  if ( v6 )
    result = j_db(v5, v4, v3); //走这里...
  return result;
}
}

**************
[Asm] 纯文本查看 复制代码
int __fastcall db(int a1, int a2, int a3)
{
  int v3; // r4
  int v4; // r5
  int v5; // r6
  int v7; // r0

  v3 = a3;
  v4 = a2;
  v5 = a1;
  if ( j_dh(a1, a2) )
    return j_ds(v5, v4, v3); 走这里
  v7 = j_getpid();
  j_kill(v7, 9);
  return 0;
}

//******************

[Asm] 纯文本查看 复制代码
int __fastcall ds(int a1, int a2, int a3)
{
  int v3; // r4
  int v4; // r0
  std::__node_alloc *v5; // r5
  std::__node_alloc *v6; // r6
  unsigned int v7; // r2
  signed int v8; // r4
  int v9; // r0
  int result; // r0
  char v11; // [sp+8h] [bp-8h]
  char v12; // [sp+Ch] [bp-4h]
  int v13; // [sp+10h] [bp+0h]
  int v14; // [sp+20h] [bp+10h]
  std::__node_alloc *v15; // [sp+24h] [bp+14h]
  int v16; // [sp+28h] [bp+18h]
  int v17; // [sp+38h] [bp+28h]
  std::__node_alloc *v18; // [sp+3Ch] [bp+2Ch]
  int v19; // [sp+40h] [bp+30h]

  v3 = a3;
  if ( j_dh(a1, a2) )
  {
    v4 = j_wolf_de("636D55B2AA8609CB");
    sub_15184(&v16, v4, &v12);///整个程序就走到了这个位置! 这里返回出来的就是正确密码hello5.1 
    sub_15184(&v13, v3, &v11);
    v5 = v18;
    v6 = v15;
    v7 = v17 - v18;
    v8 = 0;
    if ( v17 - v18 == v14 - v15 )
    {
      v8 = 1;
      if ( j_memcmp(v18, v15) )
        v8 = 0;
    }
    if ( v6 != &v13 && v6 )
    {
      j_std::__node_alloc::deallocate(v6, (v13 - v6), v7);
      v5 = v18;
    }
    if ( v5 != &v16 && v5 )
      j_std::__node_alloc::deallocate(v5, (v16 - v5), v7);
  }
  else
  {
    v9 = j_getpid();
    j_kill(v9, 9);
    v8 = 0;
  }
  result = _stack_chk_guard - v19;
  if ( _stack_chk_guard == v19 )
    result = v8;
  return result;
}



程序终于给走完了,最终密码是 hello5.1   ,这个需要在动态调试的时候,在调用
sub_15184(&v16, v4, &v12);  程序返回的是密码。
这个加密是采用rc4 加密算法 ,可以在wolf_de  里面可以跟踪到
[Asm] 纯文本查看 复制代码
 if ( j_RC4(v5, v8 >> 1, v2, v9, v7, &v11) )
        {
          v7[v11] = 0;
          v4 = v7;
        }

但是咱们呢,也不纠结是怎么得到的,只要我们能够把正确密码得到就算成功,
好了教程就到这里了,写得不好大家多多包涵,毕竟我也是刚学习安卓逆向没得多久,这段时间肺炎闹得厉害,打游戏呢,也打懵逼了,发个帖子记忆一下
有什么错误,欢迎大家指正,

链接:https://share.weiyun.com/5cr3Nm3 密码:v9q94t

免费评分

参与人数 5吾爱币 +3 热心值 +5 收起 理由
cms061817 + 1 热心回复!
wwpeng110 + 1 + 1 用心讨论,共获提升!
shuangyeying + 1 + 1 谢谢@Thanks!
Solomon + 1 + 1 用心讨论,共获提升!
wale + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| yutao531315 发表于 2020-2-17 21:54
neilwu 发表于 2020-2-17 21:51
有个偷鸡方法 如果你直接hook wolf_de这个方法(0x000169A0)可以直接拿到flag
args0 636D55B2AA8609CB
...

嗯 ,是的,这个方案可行,不过前提得会分析,找到关键点
neilwu 发表于 2020-2-17 21:51
有个偷鸡方法 如果你直接hook wolf_de这个方法(0x000169A0)可以直接拿到flag
args0 636D55B2AA8609CB
retval hello5.1
wale 发表于 2020-2-14 01:03
Solomon 发表于 2020-2-14 07:51
来支持一下楼主。。
tianaishi 发表于 2020-2-14 10:37

来支持一下楼主。。
Jackdlk 发表于 2020-2-14 14:32
来学习一下
neilwu 发表于 2020-2-15 22:55
支持一下 练练手
gypsylu 发表于 2020-2-16 11:50
感谢楼主的分享
shuangyeying 发表于 2020-2-22 00:37
哪个培训班呀,感觉想去学一波。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 16:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表