目录

安卓逆向学习

安卓逆向学习

环境搭建

Android studio安装

https://developer.android.com/studio

ADB安装

在platform-tools里面有adb.exe,直接将其添加到环境变量里面即可

方法是:打开高级系统设置->环境变量->系统变量(Path)->新建->把路径复制进去即可

adb常用命令:

adb-devices: 列出链接的设备

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230419020737664.png

adb-shell:打开设备的shell

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230419020852739.png

adb install xxx.apk: 安装APK

adb push /path/at/local /path/in/device: 把本地文件传到设备上

adb pull /path/in/device /path/at/local: 从设备上拿文件到本地

APKTOOL / APKSIGNER

APKTOOL

APKSIGNER

  • 签名工具,修改并重新打包之后的APK需要重新签名,否则无法安装

  • java –jar apksigner.jar certificate.pem key.pk8 xxx.apk xxx_signed.apk

native 逆向之编译一份自己的so库

最好安装java 8

choco install jdk8即可

choco安装如下

1
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin

android studio新建一个Native C++ project

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230420172516130.png

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230420172534611.png

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230420172731297.png

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230420172925004.png

一开始可能会下一些东西,大概等个四五十分钟,等待即可

app/src/main/java/com/example/MainActivity.java

 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
package com.example.re;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private Button mBtnVerify;
    private EditText mEtInput;

    static {
        System.loadLibrary("test");//加载libtest.so
    }

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

        mBtnVerify = findViewById(R.id.btn_verify);//确认键
        mEtInput = findViewById(R.id.et_input);//输出的内容
        mBtnVerify.setOnClickListener(view -> {//按下确认键之后的操作
            String input = mEtInput.getText().toString();//获取输入的字符串
            if (test.Hello(input)) {//调用native层函数
                Toast.makeText(MainActivity.this, "成功", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

res/layout/activity_main.xml

对应MainActivity.java里面的btn_verify和et_input

 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
<?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">

    <EditText
        android:id="@+id/et_input"
        android:layout_width="266dp"
        android:layout_height="150dp"
        android:hint="请输入数据"
        tools:layout_editor_absoluteX="89dp"
        tools:layout_editor_absoluteY="215dp" />

    <Button
        android:id="@+id/btn_verify"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="确定"
        tools:layout_editor_absoluteX="161dp"
        tools:layout_editor_absoluteY="393dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/java/com/example/test.java

用于生成类以及头文件

1
2
3
4
5
6
7
8
package com.example.re;

public class test {
    static {
        System.loadLibrary("test");//加载libtest.so
    }
    public static native boolean Hello(String input);//定义函数
}

在当前目录下执行,会生成test.Class

1
javac test.java

回到app/src/main/java目录执行,会生成com_example_re_test.h,将生成的com_example_re_test.h放入到app/src/main/cpp路径下

1
javah com.example.re.test

app/src/main/cpp/CmakeLists.txt

修改add_library、find_library、target_link_libraries

test对应我们生成的库的名字

main.c对应我们要自定义的库函数的文件

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230420174004403.png

 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
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.22.1)

# Declares and names the project.

project("re")

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        test

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        main.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        test

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        test

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

app/src/main/cpp/main.c

 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
#include "com_example_re_test.h"
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <stdlib.h>
#include "base64.h"
//static const char *BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char *BASE64_ALPHABET = "AB+/abcdefg0123456789OPQRSTUVWXYZCDEFGhijklmnopqrstuvwxyzHIJKLMN";

size_t base64_encoded_size(size_t input_len) {
    return 4 * ((input_len + 2) / 3);
}

size_t base64_decoded_size(const char *input_data, size_t input_len) {
    size_t padding = 0;

    if (input_len > 0 && input_data[input_len - 1] == '=') {
        padding++;

        if (input_len > 1 && input_data[input_len - 2] == '=') {
            padding++;
        }
    }

    return 3 * ((input_len + 3) / 4) - padding;
}

void base64_encode(char *output_data, const char *input_data, size_t input_len) {
    size_t i, j;
    unsigned char b0, b1, b2;
    unsigned int triple;

    for (i = 0, j = 0; i < input_len; i += 3, j += 4) {
        b0 = input_data[i];
        b1 = i + 1 < input_len ? input_data[i + 1] : 0;
        b2 = i + 2 < input_len ? input_data[i + 2] : 0;

        triple = (b0 << 16) | (b1 << 8) | b2;

        output_data[j] = BASE64_ALPHABET[(triple >> 18) & 0x3F];
        output_data[j + 1] = BASE64_ALPHABET[(triple >> 12) & 0x3F];
        output_data[j + 2] = BASE64_ALPHABET[(triple >> 6) & 0x3F];
        output_data[j + 3] = BASE64_ALPHABET[triple & 0x3F];
    }

    for (i = 1; i < (input_len % 3); i++) {
        output_data[j - i] = '=';
    }

    output_data[j] = '\0';
}
JNIEXPORT jboolean JNICALL Java_com_example_re_test_Hello(JNIEnv *env, jclass, jstring data){
    const char *data_str = (*env)->GetStringUTFChars(env, data, NULL);

    // Encode the input data as base64
    size_t input_len = strlen(data_str);
    size_t output_len = base64_encoded_size(input_len);
    char *encoded_data = (char*) malloc(output_len + 1);
    base64_encode(encoded_data, data_str, input_len);
    //encoded_data[output_len] = '\0';
//    return encoded_data;
//
    // Compare the encoded data to the expected value
    char *expected_data = "ShsCSyoDREau3/5zSh9v3caw18RH2hat3PeHSEeySh6C2PRwSQv=";
    int result = strncmp(encoded_data, expected_data,strlen(expected_data));

    // Free the memory allocated for the encoded data
    free(encoded_data);
    if (result == 0) {
        return JNI_TRUE;
    } else {
        return JNI_FALSE;
    }
}

app/src/main/cpp/base64.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#ifndef BASE64_H
#define BASE64_H

#include <stddef.h>

size_t base64_encoded_size(size_t input_len);
size_t base64_decoded_size(const char *input_data, size_t input_len);
void base64_encode(char *output_data, const char *input_data, size_t input_len);
size_t base64_decode(char *output_data, const char *input_data, size_t input_len);

#endif /* BASE64_H */

完成之后rebuild即可

IDA调试so

下载夜神模拟器

进入IDA\dbgsrv ,将android_x86_server

1
2
3
4
5
6
7
nox_adb connect 127.0.0.1:62001
nox_adb push ".\android_x86_server" /data/local/tmp
nox_adb shell
pm list packages -3 #列出包
am start -D -n 列出的packages/.MainActivity
cd /data/local/tmp/
chmod 777 android_x86_server && ./android_x86_server

新建一个窗口

1
nox_adb forward tcp:23946 tcp:23946

如果执行了没反应换个端口,例如1234

1
nox_adb forward tcp:1234 tcp:23946

常见命令:

netstat -tunlp 查看端口占用

kill -9 pid 杀死进程号为pid的进程

返回IDA

IDA->Debugger->remote linux debugger 配置一下,然后修改debug options

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230421010052838.png

然后attack相应的包

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230421010212121.png

https://tuchuang-1304629987.cos.ap-chengdu.myqcloud.com//image/image-20230421010223927.png