xkang 发表于 2018-8-20 16:35

安卓逆向——Frida Hook 入门教学

本帖最后由 xkang 于 2018-8-20 16:38 编辑

之前的安卓逆向内购以及简单的Hook有些小伙伴提到想了解HOOK游戏教程

寻思着讲讲于是在论坛搜了一下 Frida   发现没有   就写了这个教程   假如撞车了多尴尬{:5_184:}
成功目标获取到SECCON

上一篇帖子传送门:
安卓逆向-——实现内购以及HOOK法干掉签名校验
https://www.52hb.com/thread-39146-1-1.html
(出处: 吾爱汇编论坛)


声明:
此次教程涉及到的CODE&APK来源于Frida官网
教程环境:Mac Book Pro(Linux)

教程大纲:1.安装Frida以及genymotion模拟器&python2.7或者python3.6,ADB
                  2.调试Frida
                  3.分析APK的calc&code
                  4.HOOK APK


1.安装Frida以及genymotion模拟器&python2.7或者python3.6,ADB
    1.1安装python2.7或者python3.6
      进入官网:https://www.python.org/   选择Downloads>Windows下载相应版本   安装
    1.2安装ADB
      进入官网:http://adbshell.com/downloads选择下载ADB Kits下载安装
       注意ADB版本问题ADB版本一定要一致   比如server是40 那么client也必须是40
    1.3安装genymotion模拟器
      进入官网:http://www.genymotion.net/需要先注册在下载安装
    1.4安装Frida
      Windows打开CMD输入sudo pip install frida-tools
      Linux打开终端输入sudo pip install frida-tools
等待安装完成即可之后 终端(CMD)打开Python 输入import frida 没报错即是成功
之后需要下载Frida-server
https://github.com/frida/frida/releases/download/12.0.8/frida-server-12.0.8-android-x86.xz即可并改名为Frida-server

2.调试Frida
   终端(CMD)输入以下命令
       adb devices

这样就成功了   接下来在输入以下命令            adb root
      adb pushFrida-server/data/local/tmp/
      adb shell "chmod 755 /data/local/tmp/Frida-server"
      adb shell"/data/local/tmp/Frida-server &"
此处注意frida server开启后不要关闭另起窗口执行其他命令
之后再输入 frida-ps -U


一切OK   这样frida就可以 用了

3.分析APK的calc&code
APK下载地址:https://github.com/ctfs/write-ups-2015/tree/master/seccon-quals-ctf-2015/binary/reverse-engineering-android-apk-1
目标:Please win 1000 times in rock-paper-scissors
    3.1 分析APK
         windows将APK拖进Android Killer即可
         MAC 需要安装Android CrackTool
得到MainActivity代码
public class MainActivity
extends Activity
implements View.OnClickListener
{
Button P;
Button S;
int cnt = 0;
int flag;
private final Handler handler = new Handler();
int m;
int n;
Button r;
private final Runnable showMessageTask = new Runnable()
{
    public void run()
    {
      TextView localTextView = (TextView)MainActivity.this.findViewById(2131492946);
      MainActivity localMainActivity;//可以看出赢了cnt值加一平手和输了都归零cnt=999即可成功
      if (MainActivity.this.n - MainActivity.this.m == 1)//if (MainActivity.this.m - MainActivity.this.n == 1) 结合下面m=0,1,2   推断我们需要m,n得什么值
      {
      localMainActivity = MainActivity.this;
      localMainActivity.cnt += 1;
      localTextView.setText("WIN! +" + String.valueOf(MainActivity.this.cnt));
      }
      for (;;)
      {
      if (1000 == MainActivity.this.cnt) {//calc()算法可以通过这个直接获取到成功结果通过IDA分析 可以知道 MainActivity.this.calc() 返回固定int值7
//最终结果“107749"正确答案后面说IDA分析(1000+7)*107
          localTextView.setText("SECCON{" + String.valueOf((MainActivity.this.cnt + MainActivity.this.calc()) * 107) + "}");
      }
      MainActivity.this.flag = 0;
      return;
      if (MainActivity.this.m - MainActivity.this.n == 1)
      {
          MainActivity.this.cnt = 0;
          localTextView.setText("LOSE +0");
      }
      else if (MainActivity.this.m == MainActivity.this.n)
      {
          localTextView.setText("DRAW +" + String.valueOf(MainActivity.this.cnt));
      }
      else if (MainActivity.this.m < MainActivity.this.n)
      {
          MainActivity.this.cnt = 0;
          localTextView.setText("LOSE +0");
      }
      else
      {
          localMainActivity = MainActivity.this;
          localMainActivity.cnt += 1;
          localTextView.setText("WIN! +" + String.valueOf(MainActivity.this.cnt));
      }
      }
    }
};

static
{
    System.loadLibrary("calc");
}

public native int calc();

public void onClick(View paramView)
{
    if (this.flag == 1) {}
    for (;;)
    {
      return;
      this.flag = 1;
      ((TextView)findViewById(2131492946)).setText("");
      TextView localTextView2 = (TextView)findViewById(2131492944);
      TextView localTextView1 = (TextView)findViewById(2131492945);
      this.m = 0;
      this.n = new Random().nextInt(3);//随机三个数 代表剪刀石头布//m代表玩家n代表电脑
      int i = this.n;
      localTextView1.setText(new String[] { "CPU: Paper", "CPU: Rock", "CPU: Scissors" });//n值定电脑出什么
      if (paramView == this.P)
      {
      localTextView2.setText("YOU: Paper");
      this.m = 0;
      }
      if (paramView == this.r)
      {
      localTextView2.setText("YOU: Rock");
      this.m = 1;
      }
      if (paramView == this.S)
      {
      localTextView2.setText("YOU: Scissors");
      this.m = 2;
      }
      this.handler.postDelayed(this.showMessageTask, 1000L);//判断是否获胜达到 1000次showMessageTask()为主要方法
    }
}

protected void onCreate(Bundle paramBundle)
{
    super.onCreate(paramBundle);
    setContentView(2130968600);
    this.P = ((Button)findViewById(2131492941));
    this.S = ((Button)findViewById(2131492943));
    this.r = ((Button)findViewById(2131492942));
    this.P.setOnClickListener(this);
    this.r.setOnClickListener(this);
    this.S.setOnClickListener(this);
    this.flag = 0;
}
}




IDA分析libcalc.so

calc得7

4.HOOK APK
   4.1HOOK模块
import frida, sys

//hook代码,采用javascript编写
jscode = """
//填写javascript代码
Java.perform(function () {
//定义变量MainActivity,Java.use指定要使用的类
    var MainActivity = Java.use('包名.MainActivity');
    //hook该类下的onCreate方法,重新实现它
    MainActivity.onCreate.implementation = function () {
      //填写实现方法
    }
});
"""
//自定义回调函数
def on_message(message, data):
    if message['type'] == 'send':
      print(" {0}".format(message['payload']))
    else:
      print(message)

process = frida.get_usb_device().attach('应用完整包名')//包名通过frida-ps -U获得
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
    4.2HOOK实现
      我们只要让cnt=1000一直赢就成功了
先来看看条件首先从上面的代码可以看到只有wincnt才加一   其他都不加那我们一直赢不就好了
if (MainActivity.this.n - MainActivity.this.m == 1)
      {
      localMainActivity = MainActivity.this;
      localMainActivity.cnt += 1;
      localTextView.setText("WIN! +" + String.valueOf(MainActivity.this.cnt));
      }
      for (;;)
      {
      if (1000 == MainActivity.this.cnt) {
          localTextView.setText("SECCON{" + String.valueOf((MainActivity.this.cnt + MainActivity.this.calc()) * 107) + "}");
      }
      MainActivity.this.flag = 0;
      return;
      if (MainActivity.this.m - MainActivity.this.n == 1)
      {
          MainActivity.this.cnt = 0;
          localTextView.setText("LOSE +0");
      }
      else if (MainActivity.this.m == MainActivity.this.n)
      {
          localTextView.setText("DRAW +" + String.valueOf(MainActivity.this.cnt));
      }
      else if (MainActivity.this.m < MainActivity.this.n)
      {
          MainActivity.this.cnt = 0;
          localTextView.setText("LOSE +0");
      }
      else
      {
          localMainActivity = MainActivity.this;
          localMainActivity.cnt += 1;
          localTextView.setText("WIN! +" + String.valueOf(MainActivity.this.cnt));
      }
从这一段代码可以分析出要想一直赢那么成立的条件为m=0 n=1cnt=999
那我们只要修改m , n的值
public void onClick(View paramView)
{
    if (this.flag == 1) {}
    for (;;)
    {
      return;
      this.flag = 1;
      ((TextView)findViewById(2131492946)).setText("");
      TextView localTextView1 = (TextView)findViewById(2131492944);
      TextView localTextView2 = (TextView)findViewById(2131492945);
      this.m = 0;
      this.n = new Random().nextInt(3);
      int i = this.n;
      localTextView2.setText(new String[] { "CPU: Paper", "CPU: Rock", "CPU: Scissors" });
      if (paramView == this.P)
      {
      localTextView1.setText("YOU: Paper");
      this.m = 0;
      }
      if (paramView == this.r)
      {
      localTextView1.setText("YOU: Rock");
      this.m = 1;
      }
      if (paramView == this.S)
      {
      localTextView1.setText("YOU: Scissors");
      this.m = 2;
      }
      this.handler.postDelayed(this.showMessageTask, 1000L);
    }
}
那么需要hookonClick(View paramView)方法
import frida, sys

def on_message(message, data):
    if message['type'] == 'send':
      print(" {0}".format(message['payload']))
    else:
      print(message)

jscode = """
Java.perform(function () {
    var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
//开始hook onClick方法需要注意这个function是传参数的所以我们hook时别忘了
//public void onClick(View paramView){}
MainActivity.onClick.implementation = function (v) {
      this.onClick(v);
//修改m,n的值
      this.m.value = 0;
      this.n.value = 1;
      this.cnt.value = 999;
      send("Success!")
    }
});
"""

process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()

ok 了成功获取





有木有更简单的方法呢   显然是有的

if (1000 == MainActivity.this.cnt) {
          localTextView.setText("SECCON{" + String.valueOf((MainActivity.this.cnt + MainActivity.this.calc()) * 107) + "}");
      }

我们可以看到假设直接hook calc()方法获取返回值直接计算得到SECCON完全可以

jscode = """
Java.perform(function () {
    var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
    MainActivity.onCreate.implementation = function () {
      var returnValue = this.calc();
      var result = (1000+returnValue)*107;
console.log("returnValue:" returnValue,"resullt :" resullt )
    }
});"""

就这样了   就不贴图了   

如有什么讲的不妥的 地方    还请多多包涵

毕竟码了这么多字给个评分好不好




Shark恒 发表于 2018-8-20 17:56

讲解非常精彩,图文不易非常耗时。鼓励发布安卓逆向分析,感谢楼主分享技术!

CwithW 发表于 2018-8-20 18:46

本帖最后由 CwithW 于 2018-8-20 18:58 编辑

又有新玩具了还行

如果目标变量是一个非基本类呢 比如在ArrayList里放int

xkang 发表于 2018-8-20 20:09

CwithW 发表于 2018-8-20 18:46
又有新玩具了还行

如果目标变量是一个非基本类呢 比如在ArrayList里放int

也可以的findclass加载   在把类当参数传给hook函数

TAOGE5387 发表于 2018-8-21 10:34

新手学学 , 谢谢楼主,感谢分享

海伦泽 发表于 2018-9-29 16:24

电脑的都不是很懂 这个更是一头雾水

lyxc 发表于 2019-1-7 17:27

谢谢分享,

kanxue2018 发表于 2019-1-11 10:56

好东西,收藏了{:5_116:}

不会有你HK 发表于 2019-1-14 11:04

能用java写hook代码吗 不会js

2479387928 发表于 2019-4-5 22:20

新手学学 , 谢谢楼主,感谢分享
页: [1] 2 3
查看完整版本: 安卓逆向——Frida Hook 入门教学