0%

逆向学习 0x01安卓基础

windows配置

开启开发者人员模式

image-20240917130613989

cmd命令

dir 查看目录下的文件
cls 清屏
cd /d 从根目录下开始进入
cd .. 到上级目录
右键复制粘贴

jed不能有中文路径

在使用国外的软件时路径最好不要有中文、空格、特殊符号,计算机名不要是中文

android studio

image-20240917211606975

image-20240917211626133

真机环境配置

刷机

刷机分为线刷和卡刷

1
2
线刷		刷的比较彻底,可以刷bootloader、radio
卡刷 刷完之后需要双清、三清、四清

同样的刷机包也有两种

1
2
3
4
5
6
7
8
9
线刷包/工厂镜像包
卡刷包/OTA全量包/OTA增量包


谷歌手机工厂镜像
https://developers.google.com/android/images

线刷包的组成:
bootloader、radio、Android系统

刷机教程

https://source.android.com/source/running.html

https://mp.weixin.qq.com/s/1EySfXSucGdiuEBTfLsymA

image-20240919141352776

使用flash-all.bat文件批量处理是一键刷机,其实是可以分开刷的

1
2
3
4
5
6
7
8
adb reboot bootloader
fastboot flash boot boot.img
fastboot flash recovery recovery.img // 卡刷分区
fastboot flash system system.img
fastboot flash bootloader bootloader.img
fastboot boot <recovery_filename>. img

// 分开刷时,注意各分区镜像是否兼容

fastboot devices无法识别设备问题

1
2
安装GoogleUSB驱动(AndroidStudio中即可下载)
此电脑 ->右键管理 ->设备管理器->选中没有驱动的Android设备 ->右键更新驱动程序->选择浏览我的电脑以查找驱动程序->找到驱动所在目录->确定安装即可

root

检测是否开启root

1
2
3
4
5
6
7
8
9
10
11
手机连接电脑后,进入命令行

adb shell

如果出现 $说明目前不是root权限,#则为root

执行

su

出现 路径 :su:inaccessible or not found,则说明无法获取root权限,这个时候就需要刷入一些东西才能开启root了

Magisk下载:https://github.com/topjohnwu/Magisk/releases

1
2
3
4
5
6
7
8
adb install (Magisk所在的路径)

// 安装的是一个apk软件,在手机里打开这个软件,选择修复一个文件
// 然后将谷歌刷机包内的 boot.img 镜像推到手机中

adb push (boot.img路径) /sdcard/

// 选择这个镜像进行修补

image-20240919143537216

找到重新打包的这个镜像,将其pull到电脑上

1
adb pull (镜像路径)

然后进入bootloader模式,将镜像刷入手机

1
2
3
4
adb reboot bootloader

// 将镜像刷入boot分区
fasboot flash boot (镜像路径)

重启,打开shell,即可使用电脑root

image-20240919144322321

注意设置时间,时间不对无法正常访问互联网

image-20240919145047364

adb工作原理

adb构成

1
2
3
1、client端,在电脑上,负责发送adb命令
2、daemon守护进程adbd,在手机上,负责接收和执行adb命令
3、server端,在电脑上,负责管理client和daemon之间的通信

image-20240917212918671

1
2
3
4
5
client端将命令发送给server端
server端将命令发送给daemon端
daemon端进行执行
将执行结果,返回给server端
server端将结果再返回给client端

超级adbd

1
2
3
有两个命令可以使用:
adb root
adb remount

这个很容易分辨,adb servber进去的时候之间就是root权限

配置adb

adb.exe在SDK的platform-tools下

image-20240917215155344

image-20240917215134001

adb.exe在SDK的platform-tools下,如果嫌麻烦就需要配置环境变量

image-20240917215015286

常用命令

命令 作用
adb / adb help / adb –help 顾名思义
adb version 显示adb版本和路径
adb start-server 启动server
adb kill-server 停止server
adb devices 显示连接的设备列表
adb install || xxx.apk 通过adb安装app
adb install || -r xxx.apk 覆盖安装
adb uninstall 包名 通过adb卸载app
adb push xxx xxx 推送电脑的文件到手机
adb pull xxx xxx 拉取手机文件到电脑
adb pull xxx
adb shell 进入到手机的Linux控制台
adb -s 设备名 shell 多设备时,指定设备

logcat常用选项

命令 用法
adb logcat -help 查看帮助
adb logcat 常规显示
adb logcat -c 清除日志
adb logcat -g 显示缓冲区大小
adb logcat -G 256M 修改缓冲区大小
adb logcat -v time 设置不同的显示格式
adb logcat -v color 带颜色的显示
adb logcat -s [tagName] 根据标签名过滤日志
ps -A |grep 获取进程pid
adb logcat |findstr [pid] 根据pid过滤日志

android studio内也带有logcat,而且是页面化的logcat,更加方便

image-20240919153642610

Android扫盲

Android历史版本

1
2
3
4
5
Android 4.4以前,采用dalvik/dvm虚拟机 有一个libdvm.so 来执行Java代码
Android 4.4,里面有dvm和art虚拟机,可以切换 libdvm.so 和 libart.so art虚拟机加快了代码运行速度,在Android 4.4是可以切换的
Android 5.0及以后,使用art虚拟机,Android系统开始区分32位和64位
nexus5 32 6.0 -> 32位 (最后一款32位cpu的手机力)
nexus6p 64 6.0 -> 64位
apk基本结构
assets 资源文件(图片、音频、数据库、网页、配置文件、dll、so等)
res 资源文件(编译后的布局文件、程序图标)
lib 各种平台下使用的对应的so文件
META-INF 签名文件
resources.arsc 资源加密(语言包)
AndroidManifest.xml 清单文件(图标、界面、权限、代码执行入口)
classes.dex 源代码

image-20240919155937298

Linux常用命令

安卓是在Linux的基础上的执行的,所以说在Linux上可以执行的命令在安卓上也可以执行,但是在用法上可能会有一些细微的差别

image-20240919161358076

Linux的目录结构是层级式的树状目录结构,最上层是根目录 / ,以 / 开头的表示绝对路径

1
2
cd ~
// 在Linux中是切换到根目录,在安卓中是切换到自己的用户目录

1、在Linux内一切皆文件(包括硬件),命令实际上是系统中的一个二进制文件,在 system/bin 目录下

2、Linux中不存在扩展名,有时候为了区分才人为的添加扩展名

3、隐藏文件以 . 开头

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
ls -a
// 查看所有文件,包括隐藏文件

ls -l
// 显示详情信息
看下面的详情信息

drwxrwx--x 2 root sdcard_rw 4096 2019-10-29 07:33 Ringtones
-rw-rw---- 1 root sdcard_rw 31532262 2009-01-01 00:00 boot.img

第一个
第一位是文件形式,d代表文件夹,-代表是文件,l代表软连接,后九位,三个为一组代表不同用户操作的权限
// 软连接相当于Windows中的快捷方式

第二个表示文件个数

第三个表示创建用户

第三个表示创建用户的用户组

第四个表示文件大小,如果是文件夹就显示4096,文件就是实际大小

第五个是创建时间

第六个名字


ls -l -h
// 统计大小,将第四个文件大小的字节数转化成MB或者KB的形式
1
2
3
4
5
file
// 查看文件类型,支持使用通配符*

du
// 查看文件大小

在Linux中文件是区分大小写的,A和a这是两个不同的文件,但是在安卓中是不区分大小写的

增删改查

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
创建
touch xxx
// 创建空文件/更新文件状态

mkdir aaa
mkdir aaa bbb
// 同时创建多个目录

mkdir -p aaa/bbb
// 递归创建

删除
rmdir xxx
// 删除空目录

rm xxx
// 删除空文件

rm -rf
// -r 递归删除整个目录
// -f 强制删除且不提示确认信息


复制
cp a /sdcard/
// 复制文件不需要选项

cp a b /sdcard/
// 复制多个文件

cp -r a b
// 复制目录需要加 -r
// -r: 递归复制整个文件夹


移动
mv oldName newName
// 移动文件同时重命名


输出文件内容
cat /proc/version

其他

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
grep
-n 显示匹配行及行号
-i 忽略字母大小写
-r 递归查找

一般是和其他命令结合使用
ps -A |grep xxx


查找文件或目录
find /home -name hello
// 指定目录,递归查找文件
// 不加-name可以检索文件的内容


输出
echo
// 可以使用 echo "hello" > text 将输出内容写入文件中,这是重定向

echo "hello" >> text
// 追加+重定向


创建软连接
ln -s aaa/bbb.txt ccc
// 这个就相当于在当前文件夹下,创建了一个快捷方式,这个快捷方式叫ccc,快捷方式指向aaa/bbb.txt

Android常用目录

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
1、data/data目录
存放用户apk数据的目录,每个apk都有自己的目录,以包名命名就是放在data/data目录下,会产生一个跟Package一样的目录,这是一个私有目录,存放使用app产生的一些数据,app只能访问各自的目录,除非root权限。

2、data/app目录
用户安装的app存放在这个目录下,也是以apk的包名命名,一般文件夹内存放的是该app的apk文件

3、data/local/tmp目录
临时目录,权限比较大

4、system/app目录
存放系统自带的app

5、system/lib目录、system/lib64目录
存放app需要的so文件,lib目录下存放的是32位运行需要的so,lib64目录存放的是64位运行所需要的so文件

6、system/bin目录
存放shell命令

7、system/framework目录
Android系统所用到框架,如jar文件,XposedBridgr.jar

8、sd卡目录,不管手机有没有存储卡都会有这个目录,app操作sd卡目录需要申请权限
sd卡目录 /sdcard
这个目录有三个软连接,也就是说有四个文件夹可以访问到sd卡目录
/sdcard
/storage/self/primary
/mnt/sdcard
/storage/emulated/0

Linux权限

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
使用 ls -l 会输出详细信息,第一个参数就是该文件的权限

drwxrwx--x 2 root sdcard_rw 4096 2019-10-29 07:33 Ringtones
-rw-rw---- 1 root sdcard_rw 31532262 2009-01-01 00:00 boot.img

1、权限:
a、第0位确定文件类型
- 代表普通文件
l 代表链接,后面会使用 -> 打印出指向的真实
d 代表目录,相当于Windows的文件夹
c 代表设备文件,鼠标、键盘 /dev
b 代表是块设备,比如硬盘 /dev
b、第1-3位确定所有者拥有该文件的权限
c、第4-6位确定所属组拥有该文件的权限
d、第7-9位确定其他用户组拥有该文件的权限

2、权限的表示方式:
rwx可读可写可执行 -代表没有权限
权限还可以用数字来表示 r=4,w=2,x=1
目录和文件都是有权限的,操作目录和文件都需要有对应权限才能操作

3、其他说明
1 :硬连接数(有多少种方式可以访问他),文件一般是1,目录至少是2
root : 用户
root : 组
8 : 文件大小(字节),如果是文件夹,显示4096字节
2009-01-01 00:00 : 最后修改时间
boot.img : 文件名/软连接名
-> 软连接指向的真是文件或目录

4、chmod可以修改文件或者目录的权限
第一种方式: +、-、= 变更权限
u:所有者 g:所有组 o:其他人 a:所有人(u、g、o的总和)
1) chmod u=rwx,g=rx,o=x 文件/目录名
2) chmod o+w 文件/目录名
3) chmod a-x 文件/目录名
// a去除x权限
第二种方式:通过数字变更权限
chmod 777 xxx

// 不是所有的目录都可以这样修改的,有些需要修改selinux策略
// 自己创建的文件和目录一般可以这样修改,但是系统内置文件大概率不会被修改成功

5、权限测试
/data/datapkgName
app的私有目录,该路径下的文件,通常拷贝到sdcard目录,再pull出来

/data/local/tmp
一个权限比较大的临时目录,一般逆向人员喜欢保存文件在这里

/sdcard
6.0以下需要清单文件里申请权限
6.0以上还需要代码里动态申请权限
10.0以后还需要清单文件里做额外设置
别看adb访问sdcard很容易,其实app访问这个目录还是挺麻烦的

Android开发入门

文件目录

文字描述一下先

gradle -> wrapper -> radle-wrapper. properties 配置项目gradle版本

bui ld. gradle 描述工程整体的编译规则

gradle. properties gradle配置文件,一般无须改动

local.properties 本机环境配置,SDK、NDK路径等,一般无须改动

settings. gradle 配置哪些模块在一起编译include‘:app’只编译app

app -> build. gradle 描述当前模块的编译规则

app -> build -> outputs -> apk -> debug/release 生成的apk的存储目录

app -> build -> intermediates -> cmake -> debug/release -> obj 生成的so存储目录

libs 模块中使用了第三方jar的时候,会放这里快
src -> main -> cpp C/C++代码点
java Java代码

src -> proguard-rules. pro Java代码混淆规则

res -> drawable 用来放图片

res -> layout 用来放布局文件

res -> mipmap-hdpi 用来放应用图片,不同屏幕的适配图标

res -> values strings. xml、 public. xml

AndroidManifest. xml 清单文件,app的icon图标、四大组件的注册、权限申请

第一级目录下的文件

外面的 build.gradle 是整个工程的配置,app模块内还有一个 build.gradle

image-20240920165930965

交叉编译工具 NDK

so是手机端的可执行文件,在电脑端编译手机端的文件,就被称为交叉编译,NDK就是开发安卓端的一个交叉编译工具

NDK的路径一般是默认的,不需要去指定

image-20240920164902502

image-20240920165414195

app项目目录

image-20240920174104599

image-20240920175008639

执行入口

build.gradle配置文件

image-20240920181544849

AndroidManifest.xml文件

image-20240920204113104

application中还有若干字节点,比如四大组件的注册

表示这是一个界面,对应类名是当前包名路径下的MainActivity

带有这一条的界面,是启动界面入口

==一个activity就是一个界面,name指定这个界面绑定哪个Java类==

AndroidManifest.xml文件还会有体现最小支持的SDK版本和安卓版本,还有有申请的权限内容,上面的文件是刚创建项目时初始化的文件

app执行入口

image-20240920211541098

Application的生命周期很长,可以用来传递一些全局变量

1
2
3
使用
public static HashMap<String, String> mlnfoMap = new HahMap<>;
定义静态变量,别的类中直接通过类名引用

基本控件

Button

按钮

绑定点击事件

细算有四种

1
2
3
4
5
6
7
8
9
10
11
12
13
1、在button组件上给出Android:onClick,在这个属性上绑定一个事件,然后在页面对应的Java文件中,定义这个事件

2、在button组件上的android:id属性上,给出一个id,然后通过在页面对应的Java文件中,通过binding来获取这个id的地址值,然后实现View.OnClickListener接口重写onClick方法,绑定事件成功

3、第二种方法的一个变型。定义一个class类,让这个类实现View.OnClickListener接口,然后重写onClick方法,然后操作id值,只不过不需要通过匿名内部类来实例化方法,而是实例化刚刚的class类(多态)

4、也是第二种方法的一个变型。不需要定义一个新的class类了,而是让现有的类实现View.OnClickListener接口,重写onClick方法,然后在这个类的内部使用
但是调用的方法变多了,不再是只通过匿名内部类
button1.setOnClickListener(new MainActivity)
button1.setOnClickListener(this)
button1.setOnClickListener(MainActivity.this)

// 第四种方式是比较方便的一种方式

示例一

image-20240920220720500

这是最简单的一种绑定事件的方法,如果绑定的事件不小心忘写了,那么点击这个按钮的时候会直接导致系统崩溃,看到下面报错提示

1
2
3
Could not find method test1(View)

// 找不到test1这个方法

image-20240920220941679

示例二

image-20240921130449725

1
2
3
4
5
6
7
Button button1 = binding.button1;
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("xiaojianbang", "test: id test");
}
});

示例三

image-20240921131309219

1
2
3
4
5
6
7
8
9
10
11
// 定义一个类
class MyClick implements View.OnClickListener {

@Override
public void onClick(View view) {
Log.d("xiaojianbang", "onClick: class onClick");
}
}

// 调用
button1.setOnClickListener(new MyClick())

示例四

image-20240921132338989

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
// 直接实现View.OnClickListener接口,重写onClick方法
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

// Used to load the 'demo' library on application startup.
static {
Log.d("xiaojianbang", "static 初始值设定项: MainActivity static");
System.loadLibrary("demo");
}

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Log.d("xiaojianbang", "static 初始值设定项: MainActivity static");

binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());


Button button1 = binding.button1;

// 有三种调用的方式,下面哪种都行
button1.setOnClickListener(new MainActivity());
button1.setOnClickListener(this);
button1.setOnClickListener(MainActivity.this);
// button1.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// Log.d("xiaojianbang", "test: id test");
// }
// });
}

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

// public void test(View view) {
// Log.d("xiaojianbang", "test: test test");
// }

@Override
public void onClick(View view) {
Log.d("xiaojianbang", "onClick: Override onClick");
}
}

last

如果有多个按钮,需要区分不同的按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
button5.setOnClickListener(this);
button6.setOnClickListener(this);

public void onClick(View view) {
// 使用这个方法可以获取是传入的id
switch (view,getId()) {
case R.id.button1:
Log.d("xiaojianbang", "onClick: button1");
break;
}
}

补:
// switch需要常量来,直接传入R.id.button1是会报错的,所以还是使用if-else比较好

image-20240921144326594

Toast

Toast是一个写好了的弹出框,现在的弹框有点丑,也可以自定义一下让他华丽一点,但是没必要

image-20240921144522645

看一下定义的Toast

1
2
3
4
5
6
7
Toast.makeText(MainActivity.this, "点击button1", Toast.LENGTH_SHORT).show();

// 使用maskeText方法,传入了三个参数
// 第一个,设置弹出框在哪个页面内弹出
// 第二个,设置弹出框的内容
// 第三个,设置弹出时间,一共有两个,一个是LENGTH_SHORT,另一个是LENGTH_LONG
// 使用maskeText方法设置好了弹出框的一些参数,然后再使用show方法来实现点击按钮,显示这个设置好的弹出框
TextView

顾名思义作用是添加文字

1、在activity_main.xml直接把这个组件拖到页面上,添加成功,使用id来操作这个组件

2、

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
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
…………

private TextView text;
// 将这个变量设置为类的一个属性,方便在方法中调用

@Override
protected void onCreate(Bundle savedInstanceState) {
…………


text = binding.textView;
// 根据id绑定到这个属性中
}

…………

// 在重写方法onClick中,点击按钮的时候操作文字
@Override
public void onClick(View view) {
if (view.getId() == R.id.button1) {
Log.d("xiaojianbang", "onClick: button1");
Toast.makeText(MainActivity.this, "点击button1", Toast.LENGTH_SHORT).show();
// 将文字设置为你好
text.setText("你好");
}
}

}

这个就是TextView主要的用法

string.xml

看一个飘黄

image-20240921152201441

找到res资源目录下的values目录的string.xml文件,定义字符串

引用方式

1
2
3
4
5
在xml文件中:
@string/[name]

在Java文件中:
R.string.[name]

image-20240921153209928

image-20240921153519147

这样使用配置文件的好处非常明显,就是如果要改动字符串,只需要更改配置文件中的字符串,不需要去代码中挨个寻找

还可以进行汉化,开发弄其他语种的版本

public.xml

既然配置了字符串内容,那么在反编译中是什么样的呢

jadx

image-20240921162347280

image-20240921162049771

image-20240921163731461

jeb

image-20240921163008675

我看了一下R.java发现是读出一些东西来的

image-20240921163147479

对于jed,string.xml更是和activity_main.xml在同一个跟文件夹下

image-20240921163851305

可以看到反编译工具并不能直接的将配置在string.xml中的字符串找出来,这个时候就需要去找public.xml这个反编译后产生的文件了,包括R.java文件也是反编译后产生的

找到public.xml文件,一般是和string.xml在同一目录下

image-20240921164523066

EditText

输入框

image-20240921165212598

这个进行的一些简单操作和TextView很相似,不再进行演示了