首页
社区
课程
招聘
[原创][原创]WSA frida在arm so下断点和读取寄存器
2023-3-2 15:37 6297

[原创][原创]WSA frida在arm so下断点和读取寄存器

2023-3-2 15:37
6297

准备工作

安卓模拟器

WSA、雷电、夜神、蓝叠、MuMu

区别:WSA可以在Windows上以窗口化的形式快速打开各种app,无需前置屏幕(手机、平板主页)

Houdini

app测试程序helloworld
使用内联汇编获取arm寄存器
mainactivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.example.helloworld
 
 
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.helloworld.databinding.ActivityMainBinding
import android.widget.Button;
import android.widget.TextView
 
class MainActivity : AppCompatActivity() {
 
    private lateinit var binding: ActivityMainBinding
 
    override fun onCreate(savedInstanceState: Bundle?) {
 
 
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val button: Button = findViewById<Button>(R.id.button1)
            var text: TextView = findViewById<TextView>(R.id.text_button)
            text.text = stringFromJNI()
            button.setOnClickListener {
                text.text = stringFromJNI()+"\nstringFromJNI"
            }
 
    }
 
    /**
     * A native method that is implemented by the 'helloworld' native library,
     * which is packaged with this application.
     */
    external fun stringFromJNI(): String
 
    companion object {
        // Used to load the 'helloworld' library on application startup.
        init {
            System.loadLibrary("helloworld")
        }
    }
}

native-lib.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <jni.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <android/log.h>
#define LOG_TAG  "C_TAG"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
int _vscprintf (const char * format, va_list pargs) {
    int retval;
    va_list argcopy;
    va_copy(argcopy, pargs);
    retval = vsnprintf(NULL, 0, format, argcopy);
    va_end(argcopy);
    return retval;
}
std::string format(const char *pszFmt, ...) {
    std::string str;
    va_list args;
    va_start(args, pszFmt);
    {
        int nLength = _vscprintf(pszFmt, args);
        nLength += 1//上面返回的长度是包含\0,这里加上
        std::vector<char> vectorChars(nLength);
        snprintf(vectorChars.data(), nLength, pszFmt, args);
        str.assign(vectorChars.data());
    }
    va_end(args);
    return str;
}
 
 
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_helloworld_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
 
    unsigned int uint_r0;
    unsigned int uint_r1;
    unsigned int uint_r2;
    unsigned int uint_pc;
    unsigned int uint_r7;
    unsigned int uint_sp;
    unsigned int uint_lr;
 
    //pid_t current_tid= gettid();
    //LOGD("current tid is %d", current_tid);
 
 
    asm volatile("mov %[dest], r0"
    :[dest]"=r" (uint_r0)
    );
 
    asm volatile("mov %[dest], r1"
    :[dest]"=r" (uint_r1)
    );
 
    asm volatile("mov %[dest], r2"
    :[dest]"=r" (uint_r2)
    );
 
    asm volatile("mov %[dest], pc"
    :[dest]"=r" (uint_pc)
    );
 
    asm volatile("mov %[dest], r7"
    :[dest]"=r" (uint_r7)
    );
 
    asm volatile("mov %[dest], sp"
    :[dest]"=r" (uint_sp)
    );
 
    asm volatile("mov %[dest], lr"
    :[dest]"=r" (uint_lr)
    );
    char buff[1024];
    sprintf(buff, "pc is %x \n r0 is %x \n r1 is %x \n r2 is %x \n r7 is %x \n sp is %x \nlr is %x \n",uint_pc, uint_r0, uint_r1,uint_r2, uint_r7, uint_sp,uint_lr) ;
 
    return env->NewStringUTF(buff);
}

程序效果

图片描述

frida脚本实现断点功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//frida异常处理函数
function SetExceptionHandlerArmThum(printf,data){
    Process.setExceptionHandler(
        function (details) {
            // Give us a way to cleanly exit
            console.log('-*-------------detail:',JSON.stringify(details) );
            return false;
        }
    );
}
 
function main(){
 
    //在arm模块代码段找一地址(可以是pc) 写入0xde01
    Memory.protect(ptr(0xb698cf4), 4096, 'rwx');
    var data = Memory.readU16(addr);
    Memory.writeU16(addr,0xde01);
 
    //异常回调
    SetExceptionHandlerArmThum(addr,data)
}

运行脚本
图片描述
根据报错信息 触发了sig4 ,并且触发异常地址在libhoudini 偏移0x276aff位置

 

使用ida查看libhoudini
图片描述
可以看到libhoudini接管了arm的软中断,并且抛出信号4
验证该猜想,修改脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//只需在捕获sig4时 修复断点,返回程序
function SetExceptionHandlerArmThum(printf,data){
    Process.setExceptionHandler(
        function (details) {
            // Give us a way to cleanly exit
            console.log('-*-------------detail:',JSON.stringify(details) );
            console.log('detail:',details);
            if(details.type == 'illegal-instruction'){  //arm断点
             Memory.writeU16(printf,data); //修复断点
 
              // readRegs();//读取arm寄存器
                return true;  //继续
            }
 
            return false;
        }
    );
}

重新运行脚本,程序正常运行。断点功能以实现

获取arm寄存器

ida分析libhoudini
图片描述

 

通过查找资料syscall 会用到proc_state这个结构体,该结构体保存了寄存器数据,所以这之前会获取寄存器,猜测v2函数是获取arm寄存器的函数

 

frida脚本验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function readRegs(){
    var base = Module.findBaseAddress("libhoudini.so");///home/www/simulator_dbg/ko/1/jni/1
    // var calladdr1 = base.add(0x53fff4).add(0x2767ac).add(-2583048); //wsa -12
     var calladdr1 = base.add(0x56aff4).add(0x27837f).add(-2590151); //and9
    var calladdr2 =ptr(calladdr1).readU32();
    var call =ptr(calladdr2).readU32();
    // var argaddr1 =  base.add(0x53fff4).add(0x276752).add(-2583050); //wsa -12
    var argaddr1 =  base.add(0x56aff4).add(0x278324).add(-2590152); //and9
    var argaddr2 =ptr(argaddr1).readU32();
    var arg =   ptr(argaddr2).readU32();
    // 主动调用
    var getRegs = new NativeFunction(ptr(call), "int",["int"]);
    var ret = getRegs(arg);
    dump(ptr(ret),256)
    //dumpArm32Reg(ptr(ret).add(64))
 
 
}

结果
图片描述
图片描述
对比结果,解析寄存器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function dumpArm32Reg(addr){
    dump(ptr(ptr(addr).add(0).readU32()),256)    console.log("R0:",ptr(addr).add(0).readU32().toString(16)
    +"\tR1:",ptr(addr).add(4).readU32().toString(16)
    +"\tR2:",ptr(addr).add(8).readU32().toString(16)
    +"\tR3:",ptr(addr).add(12).readU32().toString(16)
    +"\tR4:",ptr(addr).add(16).readU32().toString(16)
    +"\nR5:",ptr(addr).add(20).readU32().toString(16)
    +"\tR6:",ptr(addr).add(24).readU32().toString(16)
    +"\tR7:",ptr(addr).add(28).readU32().toString(16)
    +"\tR8:",ptr(addr).add(32).readU32().toString(16)
    +"\nR9:",ptr(addr).add(36).readU32().toString(16)
    +"\tR10:",ptr(addr).add(40).readU32().toString(16)
    +"\tR11:",ptr(addr).add(44).readU32().toString(16)
    +"\tR12:",ptr(addr).add(48).readU32().toString(16)
    +"\nSP:",ptr(addr).add(52).readU32().toString(16)
    +"\tLR:",ptr(addr).add(56).readU32().toString(16)
    +"\tPC:",ptr(addr).add(60).readU32().toString(16)
    +"\tcpsr1:",ptr(addr).add(64).readU32().toString(16)
    +"\tspsr:",ptr(addr).add(68).readU32().toString(16));
}

结果
图片描述

总结

经过测试该方法使用与安卓9,libhouni5以上的任意模拟器
我们后续开发了基于drawf的可视化调试器


阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 1494
活跃值: (125)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
a'ゞCicada 1 2024-3-5 20:37
2
0
现在怎么样了
游客
登录 | 注册 方可回帖
返回