首页
社区
课程
招聘
[分享][原创]FRIDA高级功能
发表于: 2020-12-15 19:34 5561

[分享][原创]FRIDA高级功能

2020-12-15 19:34
5561

多台设备

连接多台设备还是很简单的,使用Frida作者oleavr(很多人称他是大胡子,以后就用这个称呼了)为我门提供的python binding功能。当然前提是相应设备的frida-server已经开了。

根据设备id就可以获取相应设备的device。使用的函数是get_device。

在这里插入图片描述

互联互通

互联互通是指把app中捕获的内容传输到电脑上,电脑上处理结束后再发回给app继续处理。看似很简单的一个功能,目前却仅有Frida可以实现。后面的这句话我不清楚是否真假,就我所知道的,它是真的,不过通过这句话也能感受到Firda的强大。

预备知识

recv([type, ]callback): request callback to be called on the next message received from your Frida-based application. Optionally type may be specified to only receive a message where the type field is set to type. This will only give you one message, so you need to call recv() again to receive the next one.send(message[, data]): send the JavaScript object message to your Frida-based application (it must be serializable to JSON). If you also have some raw binary data that you’d like to send along with it, e.g. you dumped some memory using NativePointer#readByteArray, then you may pass this through the optional data argument. This requires it to either be an ArrayBuffer or an array of integers between 0 and 255.

App

页面

简单的登陆页面如下图:在这里插入图片描述

功能

admin账户不能用来登陆,这个只是在前台进行的校验。对账户密码进行base64编码发送给服务器。

源代码

功能代码:


package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


   EditText username_et;
   EditText password_et;
   TextView message_tv;

   // Used to load the 'native-lib' library on application startup.
   static {
       System.loadLibrary("native-lib");
   }

   @Override
   protected void onCreate(Bundle savedInstanceState) {
     //  super.onCreate(savedInstanceState);
       //setContentView(R.layout.activity_main);

       // Example of a call to a native method
       //TextView tv = findViewById(R.id.sample_text);
       //tv.setText(stringFromJNI());
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       password_et = (EditText) this.findViewById(R.id.password);
       username_et = (EditText) this.findViewById(R.id.username);
       message_tv = ((TextView) findViewById(R.id.textView));

       this.findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {

               if (username_et.getText().toString().compareTo("admin") == 0) {
                   message_tv.setText("You cannot login as admin");
                   return;
               }
               //我们hook的目标就在这里
               message_tv.setText("Sending to the server :" + Base64.encodeToString((username_et.getText().toString() + ":" + password_et.getText().toString()).getBytes(), Base64.DEFAULT));

           }
       });

   }

   /**
    * A native method that is implemented by the 'native-lib' native library,
    * which is packaged with this application.
    */
   public native String stringFromJNI();
}


布局代码:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">


   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_height="match_parent"
       android:layout_width="match_parent">


   <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="用户名"
       android:textSize="24sp" />

   <EditText
       android:id="@+id/username"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:hint="请输入您的用户名"/>

   <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="密码"
       android:textSize="24sp" />

   <EditText
       android:id="@+id/password"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:hint="请输入您的密码"/>

  <TextView
       android:id = "@+id/textView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="请输入用户名和密码"
       android:textAlignment="center"
       android:textSize="24sp" />

   <Button
       android:id="@+id/login"
       android:layout_height="60dp"
       android:layout_width="wrap_content"
       android:text="登录"
       android:layout_gravity="center"
       android:textAlignment="center"
       android:textSize="18sp" />
   </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>


布局类介绍: A ConstraintLayout is a android.view.ViewGroup which allows you to position and size widgets in a flexible way. LinearLayout is a layout that arranges other views either horizontally in a single column or vertically in a single row.

通过hook修改逻辑

(1)实现能够让admin登陆,绕过前台的校验。 (2)将setText中文本发送给电脑端,通过电脑端对数据进行修改,然后把修改后的内容再次发送给手机。也就是互联互通。

python代码(python3.8):


import time
import frida
import sys
import base64

def my_message_handler(message, payload):
   print(message)
   print(payload)
   if message["type"] == "send":
       print(message["payload"])
       data = message["payload"].split(":")[1].strip()
       print('message:', message)
       print("burning data:"+data)
       data = str(base64.b64decode(data), "utf-8")# 解码
       user, pw = data.split(":") # 提取用户名和密码
       data  =  str(base64.b64encode(("admin" + ":" + pw).encode("utf-8")), "utf-8") # 组成新的组合并编码,这是使用admin登陆
       print("encoded data:", data)
       script.post({"my_data": data})  # 将JSON对象发送回去
       print("Modified data sent")

device = frida.get_usb_device()
pid = device.spawn(["com.example.myapplication"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("conn.js") as f:
   script = session.create_script(f.read())
script.on("message", my_message_handler)  # 注册消息处理函数
script.load()
sys.stdin.read()


conn.js代码:


Java.perform(function () {
   var tv_class = Java.use("android.widget.TextView");
   tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) {
       var string_to_send = x.toString();
       var string_to_recv;
       console.log("send"+string_to_send);
       send(string_to_send); // 将数据发送给PC端
       recv(function (received_json_object) {
           string_to_recv = received_json_object.my_data
           console.log("string_to_recv: " + string_to_recv);
       }).wait(); //收到数据之后,再执行下去
       var string = Java.use("java.lang.String");
       string_to_recv = string.$new(string_to_recv);//将收到的数据转化为String类型
       return this.setText(string_to_recv);
   }
});


又很多数据通过JavaScript处理起来可能比较麻烦,那么可以考虑把数据发送给PC端,在PC端用python对数据处理就容易多了,处理完成之后再把数据发送回去。

远程调用(RPC)

在 Frida API使用(1) 对RPC进行了介绍。在文章中把js和python代码写在了一个文件中,最好是把他们分开写,这里不再举例。

这个定义还是很重要的: rpc.exports is empty object that you can either replace or insert into to expose an RPC-style API to your application. The key specifies the method name and the value is your exported function.

文件操作

在 Frida API进阶-文件 对文件操作进行了介绍.但是没有涉及到读具体文件的操作, 这里补充上.


function get_self_process_name() {
   var openPtr = Module.getExportByName('libc.so', 'open');
   var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);

   var readPtr = Module.getExportByName("libc.so", "read");
   var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]);

   var closePtr = Module.getExportByName('libc.so', 'close');
   var close = new NativeFunction(closePtr, 'int', ['int']);

   var path = Memory.allocUtf8String("/proc/self/cmdline");
   var fd = open(path, 0);
   if (fd != -1) {
       var buffer = Memory.alloc(0x1000);

       var result = read(fd, buffer, 0x1000);
       close(fd);
       result = ptr(buffer).readCString();
       console.log("进程的名字是:"+result);
       return result;
   }

   return "-1";
}


上面代码的功能是获取当前进程的名字.在这里插入图片描述

写在最后

再前面的apk中,通过hook技术很容易绕过了前台的校验,由此可见,前台的校验是多么的不靠谱.这种校验最好都放在后台,

公众号

更多Frida的内容,欢迎关注我的微信公众号:无情剑客.在这里插入图片描述


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 1931
活跃值: (442)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这好类似论坛大佬 r0ysue的文章嘛 https://github.com/r0ysue/AndroidSecurityStudy
2020-12-15 19:40
0
雪    币: 110
活跃值: (670)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
难道这不是常规操作么
2020-12-15 19:43
0
雪    币: 443
活跃值: (1157)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
TopGreen 这好类似论坛大佬 r0ysue的文章嘛 https://github.com/r0ysue/AndroidSecurityStudy

很多参考r0ysue的文章。完善了一些不太完美的地方。补充了一些功能,比如断点,未到出符号的hook,数据类型转化

最后于 2020-12-15 21:46 被无情剑客_bur编辑 ,原因:
2020-12-15 21:29
0
雪    币: 443
活跃值: (1157)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
yzlmars 难道这不是常规操作么
个人理解互联互通功能还是很强的。
2020-12-15 21:30
0
雪    币: 634
活跃值: (1503)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
RPC可以并发么?
2020-12-16 09:29
0
雪    币: 110
活跃值: (670)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
无情剑客_bur TopGreen 这好类似论坛大佬 r0ysue的文章嘛 https://github.com/r0ysue/AndroidSecurityStudy 很多参考 ...
frida可以下断点,单步调试吗?那篇文章有介绍
2020-12-16 10:26
0
雪    币: 443
活跃值: (1157)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
yzlmars frida可以下断点,单步调试吗?那篇文章有介绍
能下断点,硬件断点。单步调试目前还在探索中。
2020-12-16 12:41
0
游客
登录 | 注册 方可回帖
返回
//