首页
社区
课程
招聘
[原创]通过模拟触摸屏控制器驱动来实现手机点击,滑动操作
2023-12-16 01:28 6928

[原创]通过模拟触摸屏控制器驱动来实现手机点击,滑动操作

2023-12-16 01:28
6928
1
本人是武汉科锐毕业生,写该工具目的是用来学习内核知识的,忘各位大佬指点

该项目主要作用是模拟驱动来实现对触摸屏的操控。如:滑动,点击操作。

项目大致代码简介

1
整个分为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
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    文件synaptics_dsx_core.c,该驱动为内核原本的驱动,其中添加了函数synaptics_rmi4_f12_abs_report_me为关键代码用来向输入子系统报告触摸屏操作。通过封装synaptics_rmi4_f12_abs_report_me实现2个函数,set_input_touch_slide,set_input_touch_click分别实现滑动和点击事件
 
//该函数为实现触摸关键函数
//stop为控制是触摸还是停止,true为手指离开,false为手指还在屏幕上
//x,y位坐标
static int synaptics_rmi4_f12_abs_report_me(bool stop,int x,int y)
{
    int wx;
    int wy;
    //判断是手指是否离开触摸屏
    if(stop == true){
        data_me.object_type_and_status = 20;
    }else{
        data_me.object_type_and_status = F12_FINGER_STATUS;
    }
 
    wx = 0;
    wy = 0;
 
    switch (data_me.object_type_and_status) {
    case F12_FINGER_STATUS:
    case F12_GLOVED_FINGER_STATUS:
        /* Stylus has priority over fingers */     
        printk(KERN_ALERT "zeyu F12_GLOVED_FINGER_STATUS\n");
        //向输入子系统报告触摸屏触摸信息,p_inputdev为触摸屏设备的指针,该指针我是通过正常驱动函数中拿到的,当然也可以通过其他途径,大家自行考虑
        input_mt_slot(p_inputdev,0);
        input_mt_report_slot_state(p_inputdev,
                MT_TOOL_FINGER, 1);
 
        input_report_key(p_inputdev,
                BTN_TOUCH, 1);
        input_report_key(p_inputdev,
                BTN_TOOL_FINGER, 1);
        input_report_abs(p_inputdev,
                ABS_MT_POSITION_X, x);
        input_report_abs(p_inputdev,
                ABS_MT_POSITION_Y, y);
        input_report_abs(p_inputdev,
                ABS_MT_TOUCH_MAJOR,
                synaptics_sqrt(wx*wx + wy*wy));
        input_report_abs(p_inputdev,
                ABS_MT_TOUCH_MINOR,
                min(wx, wy));
 
 
        input_report_abs(p_inputdev,
                ABS_MT_PRESSURE, 1);
             
             
        break;
    default:
        //当手指离开触摸屏时执行到这里
        printk(KERN_ALERT "zeyu default\n");
        input_mt_slot(p_inputdev, 0);
        input_mt_report_slot_state(p_inputdev,
                    MT_TOOL_FINGER, 0);
        break;
    }
     
    //该函数执行立即同步,不然会有延迟
    input_sync(p_inputdev);
 
    return 0;
     
}
 
 
 
 
//该函数为实现点击触摸屏
void set_input_touch_click(int x,int y)
{
    //这是为了模拟更像所以多调用几次
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    synaptics_rmi4_f12_abs_report_me(false,x,y);
    //手指离开屏幕(如果不设置,则表示为长时间触摸该位置)
    synaptics_rmi4_f12_abs_report_me(true,x,y);
    return;
}
//该代码作用为将该符号到处给其他驱动使用
EXPORT_SYMBOL(set_input_touch_click);
 
 
//该函数实现滑动触摸屏,为开始的位置到停止的位置,可以看到我都是分为9次移动过去,系统会通过判断时间等来判断点击和移动的。其中代码就不仔细分析了。
void set_input_touch_slide(int start_x,int start_y,int end_x,int end_y)
{
    int tmp_x = 0;
    int tmp_y = 0;
    int zeyu_x = 0;
    int zeyu_y = 0;
    size_t i = 0;
    if ((end_x == start_x) && (end_y == start_y)) {
        return;
    }
    if ((end_x >= start_x) && (end_y >= start_y)) {
        tmp_x = end_x - start_x;
        tmp_y = end_y - start_y;
        tmp_x = tmp_x / 9;
        tmp_y = tmp_y / 9;
        for (i = 0; i <= 9; i++)
        {
            zeyu_x = start_x + (tmp_x * i);
            zeyu_y = start_y + (tmp_y * i);
            if (i == 9) {
                zeyu_x = end_x;
                zeyu_y = end_y;
            }
            synaptics_rmi4_f12_abs_report_me(false,zeyu_x,zeyu_y);
            }
        synaptics_rmi4_f12_abs_report_me(true,0,0);
            return;
        }
    if ((end_x >= start_x) && (end_y <= start_y)) {
        tmp_x = end_x - start_x;
            tmp_y = start_y - end_y;
            tmp_x = tmp_x / 9;
            tmp_y = tmp_y / 9;
            for (i = 0; i <= 9; i++)
            {
                    zeyu_x = start_x + (tmp_x * i);
                    zeyu_y = start_y - (tmp_y * i);
                    if (i == 9) {
                        zeyu_x = end_x;
                        zeyu_y = end_y;
                    }
                    synaptics_rmi4_f12_abs_report_me(false,zeyu_x,zeyu_y);
            }
        synaptics_rmi4_f12_abs_report_me(true,0,0);
            return;
        }
    if ((end_x <= start_x) && (end_y >= start_y)) {
            tmp_x = start_x - end_x;
            tmp_y = end_y - start_y;
            tmp_x = tmp_x / 9;
            tmp_y = tmp_y / 9;
            for (i = 0; i <= 9; i++)
            {
                    zeyu_x = start_x - (tmp_x * i);
                    zeyu_y = start_y + (tmp_y * i);
                    if (i == 9) {
                        zeyu_x = end_x;
                        zeyu_y = end_y;
                    }
                    synaptics_rmi4_f12_abs_report_me(false,zeyu_x,zeyu_y);
            }
        synaptics_rmi4_f12_abs_report_me(true,0,0);
            return;
        }
    if ((end_x <= start_x) && (end_y <= start_y)) {
            tmp_x = start_x - end_x;
            tmp_y = start_y - end_y;
            tmp_x = tmp_x / 9;
            tmp_y = tmp_y / 9;
            for (i = 0; i <= 9; i++)
            {
                    zeyu_x = start_x - (tmp_x * i);
                    zeyu_y = start_y - (tmp_y * i);
                    if (i == 9) {
                        zeyu_x = end_x;
                        zeyu_y = end_y;
                    }
                    synaptics_rmi4_f12_abs_report_me(false,zeyu_x,zeyu_y);
            }
        synaptics_rmi4_f12_abs_report_me(true,0,0);
               return;
        }
    return;
}
EXPORT_SYMBOL(set_input_touch_slide);

自己的驱动部分:

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
    文件hello.c,该驱动的主要作用是为了打通用户层,使得用户层可以通过ioctl来通过该驱动来调用synaptics_dsx_core.c内的函数。所以该驱动只是在/dev下创建一个文件。如果大家懂windows驱动的话很相似
主要代码都是在初始化代码来创建该文件
 
//设备类别和设备变量
static struct class* g_class = 0;
dev_t devno = 0;
static struct cdev* dev = 0;
char lele[0x10] = "zeyudev";
//在dev下创建文件,但该文件是root属性
static int hello_init(void)
{
    int err = -1;
    struct device* temp = NULL;
    printk(KERN_ALERT "zeyu Hello, world\n");
 
    //动态分配主设备号与从设备号
    err = alloc_chrdev_region(&devno,0,1,"zeyu_dev");
    if(err < 0){
        printk(KERN_ALERT "zeyu alloc_chrdev_region erro\n");
    }
 
    dev = kmalloc(sizeof(struct cdev),GFP_KERNEL);
    if(!dev){
        printk(KERN_ALERT "zeyu kmalloc erro\n");
    }
    memset(dev,0,sizeof(struct cdev));
    //初始化设备,初始化结构体h_ops结构体为函数指针,用来控制open,close等对文件操作的回调函数。
    cdev_init(dev,&h_ops);
    dev->owner = THIS_MODULE;
    dev->ops = &h_ops;
 
    //注册字符串设备
    err = cdev_add(dev,devno,1);
    if(err < 0){
        printk(KERN_ALERT "zeyu cdev_add erro\n");
    }
 
    ///sys/class/下创建设备类别目录
    g_class = class_create(THIS_MODULE,"zeyu_dev");
    if(IS_ERR(g_class)){
        printk(KERN_ALERT "zeyu g_class erro\n");
    }
 
    ///dev目录和/sys/class目录下分别创建文件
    temp = device_create(g_class,NULL,devno,"%s","zeyudev");
    if(IS_ERR(temp)){
        printk(KERN_ALERT "zeyu device_create erro\n");
    }
    return 0;
}
 
//该函数为驱动的控制函数
static long myDev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
    struct zeyu_io_cmd_data data = {0};
    struct zeyu_io_cmd_data* data_user_add = 0;
    unsigned long ret = 0;
    data_user_add = (struct zeyu_io_cmd_data*)arg;
    //将用户层数据copy到内核中
    ret = copy_from_user((void *)(&data),(void __user*)data_user_add,sizeof(data));
    switch(data.cmd){
    //执行点击
    case INPUT_TOUCH_CLICK:
        set_input_touch_click(data.x,data.y);
        break;
   //执行滑动
    case INPUT_TOUCH_SLIDE:
        set_input_touch_slide(data.x_start,data.y_start,data.x_end,data.y_end);
        break;
    }
    return 0;
}
 
其他函数就不介绍了

用户层部分:

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
    文件my_dev_user.cpp,打开自己的驱动文件然后通过自定义zeyu_io_cmd_data结构体传送数据,来实现点击。
 
int main(int argc, char *argv[]){
    int fd = open("/dev/zeyudev",O_RDWR);
    if(fd < 0){
        printf("open err");
    }
    struct zeyu_io_cmd_data data = {0};
    for(int i = 0;i <= 100;i++){
        data.cmd = INPUT_TOUCH_CLICK;
        data.x = 1049;
        data.y = 725;
        ioctl(fd,0,&data);
        //暂停一下,将点击与滑动操作分开
        usleep(3000000);
 
        data.cmd = INPUT_TOUCH_SLIDE;
        data.x_start = 614;
        data.y_start = 1401;
        data.x_end = 645;
        data.y_end = 254;
        ioctl(fd,0,&data);
        usleep(3000000);
    }
 
 
    close(fd);
    printf("main end");
    return 0;
}

本人使用该代码,尝试在真机上在某社交app执行点赞以及滑动下一个视频动作。

这是在下的项目地址:
https://github.com/2290474055/marlin_touch_set_input/tree/main

该手机使用的是真机piexl 1,系统版本是android10

实现所有代码步骤

编译marlin内核

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
下载内核源码
android的官方reop分支
https://source.android.google.cn/docs/setup/build/building-kernels?hl=zh-cn
我使用的分支,因为我的版本是android10
repo init -u https://android.googlesource.com/kernel/manifest -b android-msm-marlin-3.18-android10
repo sync -j4
 
创建编译环境
该网站写了在ubuntu的版本所需要的环境
https://source.android.google.cn/docs/setup/start/initializing?hl=zh-cn
 
export PATH=$PATH:clang/bin
export PATH=$PATH:gcc/bin
export PATH=$PATH:32位gcc/bin
设置编译器,使用内核代码中的就可以
 
编译内核
1.若没有build/build.sh文件
cd ./private/msm-google进入该目录下
make O=out ARCH=arm64 marlin_defconfig,这是为了获取.config配置文件
make -j2 O=out ARCH=arm64 CC=aarch64-linux-android-gcc CLANG_TRIPLE=aarch64-linux-gnu- CROSS_COMPILE=aarch64-linux-android- CROSS_COMPILE_ARM32=arm-linux-androideabi-
2.若存在build/build.sh文件
build/build.sh即可
 
刷入临时内核
adb reboot bootloader
fastboot boot Image.lz4-dtb
若想使用该内核替代aosp的内核可以设置变量
export TARGET_PREBUILT_KERNEL=DIST_DIR/Image.lz4-dtb
至此内核编译完成。

内核中添加代码

系统驱动

直接使用synaptics_dsx_core.c替换掉原先的驱动中的该文件,位于/private/msm-google/drivers/input/touchscreeen/synaptics_dsx_htc_2.6/synaptics_dsx_core.c

写自己的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
29
30
31
32
/private/msm-google/drivers下创建目录me_drivers,创建文件hello.c,该文件中首先需要一个内核模块的加载和卸载函数。
static int hello_init(void)
{
    printk(KERN_ALERT "zeyu Hello, world\n");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "zeyuu Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
 
创建文件Makefile来编译该文件,文件中写
obj -$(CONFIG_ME_DRIVERS) =+ hello.o
 
创建文件Kconfig,这是为了在自定义图形编辑配置文件时可以找到我们的模块
config ME_DRIVERS
    tristate "ME_DRIVERS"
    default y
    help
        me drives
这样应该默认make O=out ARCH=arm64 marlin_defconfig时,得到的.config文件中就会有CONFIG_ME_DRIVERS=y
 
 
需要在/private/msm-google/drivers目录的makefile文件中添加
obj -$(CONFIG_ME_DRIVERS) =+ me_drivers/
 
需要在/private/msm-google/drivers目录的Kconfig中添加
source "drivers/me_drivers/Kconfig"
然后编译就会发现内核日志显示驱动加载进内核了。
只需要将我的hello.c替换就可以了。

用户层代码

只需要创建一个android工程的c++版本,然后创建my_dev_user.cpp文件正常写c++代码或者c代码,或者将我的文件直接拷贝放到这里
在cmake中添加代码
add_executable(text_my_dev my_dev_user.cpp)
即可编译为elf可执行文件

至此,所有代码步骤完成。

原理

在Linux输入子系统中报告触摸屏输入事件,通过调用
input_mt_slot(p_inputdev,0);
input_mt_report_slot_state(p_inputdev,MT_TOOL_FINGER, 1);
input_report_key(p_inputdev,BTN_TOUCH, 1);
input_report_key(p_inputdev,BTN_TOOL_FINGER, 1);
input_report_abs(p_inputdev,ABS_MT_POSITION_X, x);
input_report_abs(p_inputdev,ABS_MT_POSITION_Y, y);
input_report_abs(p_inputdev,ABS_MT_TOUCH_MAJOR,
synaptics_sqrt(wxwx + wywy));
input_report_abs(p_inputdev,ABS_MT_TOUCH_MINOR,min(wx, wy));
input_report_abs(p_inputdev,ABS_MT_PRESSURE, 1);

依据此原理,是可以通过构建android动态加载的驱动ko文件可以制作一个通用驱动。但本人并没有深入继续研究该目标。仅供需要的大佬考虑。


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2023-12-21 01:54 被琳宇编辑 ,原因: 补充
收藏
点赞6
打赏
分享
最新回复 (10)
雪    币: 2192
活跃值: (3497)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
R0g 2 2023-12-16 08:44
2
1
支持!
雪    币: 6
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_ldbucrik 2023-12-16 15:46
3
0
点赞
雪    币: 1109
活跃值: (1634)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_lpcoesnt 2023-12-16 18:58
4
0
为啥不用autojs呢?
雪    币: 19349
活跃值: (28971)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-12-16 23:19
5
0
感谢分享
雪    币: 129
活跃值: (1243)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
琳宇 2023-12-16 23:33
6
0
mb_lpcoesnt 为啥不用autojs呢?
是的,但是本人为了学习内核而写的。
雪    币: 1954
活跃值: (3653)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
method 2023-12-18 18:55
7
0
只有成果 没有过程
雪    币: 14
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_wxmrqhty 2024-1-6 06:32
8
0

很棒的思路

最后于 2024-1-6 06:33 被mb_wxmrqhty编辑 ,原因:
雪    币: 291
活跃值: (213372)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
shinratensei 1 2024-1-8 09:48
9
0
tql
雪    币: 235
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
南风焓 2024-4-19 08:06
10
0
需要root吗?
游客
登录 | 注册 方可回帖
返回