-
2021-02-05 21:18:33
文章首发微信公众号:QDROID88888,如果感兴趣可以关注一下公众号。
一、测试gps定位功能的方法探讨
在安卓App gps定位开发过程中,往往需要进行GPS定位的测试。由于室内gps信号被挡住了,所以如果需要测试gps定位的代码,要么跑到室外去等待gps定位更新或者使用安卓sdk中提供的"MOCK_LOCATION"功能编写额外的测试代码来模拟gps位置更新。如果从系统定制的角度出发,也可以根据gps上报的流程来模拟gps上报的逻辑实现模拟gps 的定位数据。
二、修改系统实现模拟gps数据上报
2.1 安卓系统上报gps数据流程总结
在之前的文章安卓10源码开发定制(21)GPS定位研究(2)gps位置改变监听源码分析中已经分析安卓系统中gps数据上报的大概流程:
1. 当gps位置改变更新,com_android_server_location_GnssLocationProvider.cpp中通过反射调用GnssLocationProvider.java中的reportLocation方法将gps数据上报到安卓系统java层。
2. GnssLocationProvider.java中使用LocationProvider.java提供的onReportLocation方法将gps数据上报到GPS 位置管理器。
3
更多相关内容 -
android地理位置信息修改
2017-11-09 12:47:41android 地理位置信息修改 Android中修改地理位置信息 -
第二十期 在Android中修改GPS定位数据的完整方案《手机就是开发板》
2019-01-12 11:00:06现在很多的应用都是基于位置服务的,而且把位置服务作为重要的参考标准,其实这是很不安全的,位置信息的...这一期我们来探讨一下如何修改手机中的定位信息。太基础的原理我就不多说了,可以参考前几期文章。 ...https://blog.csdn.net/aggresss/article/details/54323034
现在很多的应用都是基于位置服务的,而且把位置服务作为重要的参考标准,其实这是很不安全的,位置信息的数据未经过任何加密,而且是从我们的手机中发送出去的,所以是可以修改的。这一期我们来探讨一下如何修改手机中的定位信息。太基础的原理我就不多说了,可以参考前几期文章。
先整理一下思路,Android在开发者模式下有一个"允许模拟位置选项",它是location service加载 MOCK location provider 实现的,通过这种线程注入的方式修改GPS信息是hacker们最喜欢的方式,但现在很多应用已经可以检测到这种注入方式而被屏蔽掉,也就是说如果我们只在APP层面上想解决方法总是有被检测出来的可能。那我们就得把问题往深了想,通过修改最底层的GPS数据来欺骗APP,在Framework层面上没有任何修改迹象,这样基于APP层面的检测机制就拿我们没有任何办法。
思路确定后我们来探讨实践路线,首先我们要建立一个管道,让我们想要定位的GPS数据提交到Android操作系统的最底层,也就是Linux Kernel层面;然后我们要修改 GPS的 location report 机制,让它从内核中提取到我们的数据,然后逐层上报到APP层。有点明修栈道暗度陈仓的感觉。
总体来说分成两部实现:1.建立到系统内核的数据管道;2.修改GPS上报机制。
这次实验使用的是闲置的小米3W手机,编译源码采用CyanogenMod-13,具体的编译环境搭建和编译方法请参考前几期文章。
因为Android系统从内核态到APP层要经过很多的层次,所以对于建立数据管道的步骤比较繁琐,我这里分成了5个步骤,对应5个层面来实现,每一步分别对应Android的 Kernel driver,HAL,JNI,Framework,Application。所有的代码我都已上传github中https://github.com/aggresss/PHDemo/ 这一期的代码在VirtualPosition 目录下。
下面描述一下实践步骤:
=============分割线1==============
第一步,修改Kernel driver
进入 kernel/xiaomi/cancro/drivers 目录下,新建vp.h文件#ifndef _VP_ANDROID_H_ #define _VP_ANDROID_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define VP_DEVICE_NODE_NAME "vp" #define VP_DEVICE_FILE_NAME "vp" #define VP_DEVICE_PROC_NAME "vp" #define VP_DEVICE_CLASS_NAME "vp" typedef struct { int toggle; double virtual_latitude; double virtual_longitude; } VirtualPosition; struct vp_android_dev { int lamp; VirtualPosition val; struct semaphore sem; struct cdev dev; }; #endif
新建vp.c文件/******************************************* *include file and define functions *******************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/device.h> #include <asm/uaccess.h> #include "vp.h" /*主设备和从设备号变量*/ static int vp_major = 0; static int vp_minor = 0; /*设备类别和设备变量*/ static struct class* vp_class = NULL; static struct vp_android_dev* vp_dev = NULL; /*传统的设备文件操作方法*/ static int vp_open(struct inode* inode, struct file* filp); static int vp_release(struct inode* inode, struct file* filp); static ssize_t vp_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos); static ssize_t vp_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos); /*设备文件操作方法表*/ static struct file_operations vp_fops = { .owner = THIS_MODULE, .open = vp_open, .release = vp_release, .read = vp_read, .write = vp_write, }; /*访问设置属性方法*/ static ssize_t vp_lamp_show(struct device* dev, struct device_attribute* attr, char* buf); static ssize_t vp_lamp_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); /*定义设备属性*/ static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, vp_lamp_show, vp_lamp_store); /******************************************* *define traditional file access *******************************************/ /*打开设备方法*/ static int vp_open(struct inode* inode, struct file* filp) { struct vp_android_dev* dev; /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/ dev = container_of(inode->i_cdev, struct vp_android_dev, dev); filp->private_data = dev; return 0; } /*设备文件释放时调用,空实现*/ static int vp_release(struct inode* inode, struct file* filp) { return 0; } /*读取设备的寄存器val的值*/ static ssize_t vp_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) { ssize_t err = 0; struct vp_android_dev* dev = filp->private_data; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count < sizeof(dev->val)) { goto out; } /*将寄存器val的值拷贝到用户提供的缓冲区*/ if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } /*写设备的寄存器值val*/ static ssize_t vp_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) { struct vp_android_dev* dev = filp->private_data; ssize_t err = 0; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count != sizeof(dev->val)) { goto out; } /*将用户提供的缓冲区的值写到设备寄存器去*/ if(copy_from_user(&(dev->val), buf, count)) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } /******************************************* *define devfs access *******************************************/ /*读取寄存器lamp的值到缓冲区buf中,内部使用*/ static ssize_t __vp_get_lamp(struct vp_android_dev* dev, char* buf) { int lamp = 0; /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } lamp = dev->lamp; up(&(dev->sem)); return snprintf(buf, PAGE_SIZE, "%d\n", lamp); } /*把缓冲区buf的值写到设备寄存器lamp中去,内部使用*/ static ssize_t __vp_set_lamp(struct vp_android_dev* dev, const char* buf, size_t count) { int lamp = 0; /*将字符串转换成数字*/ lamp = simple_strtol(buf, NULL, 10); /*同步访问*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } dev->lamp = lamp; up(&(dev->sem)); return count; } /*读取设备属性lamp*/ static ssize_t vp_lamp_show(struct device* dev, struct device_attribute* attr, char* buf) { struct vp_android_dev* hdev = (struct vp_android_dev*)dev_get_drvdata(dev); return __vp_get_lamp(hdev, buf); } /*写设备属性lamp*/ static ssize_t vp_lamp_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { struct vp_android_dev* hdev = (struct vp_android_dev*)dev_get_drvdata(dev); return __vp_set_lamp(hdev, buf, count); } /******************************************* *define proc access *******************************************/ /*读取设备寄存器lamp的值,保存在page缓冲区中*/ static ssize_t vp_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) { if(off > 0) { *eof = 1; return 0; } return __vp_get_lamp(vp_dev, page); } /*把缓冲区的值buff保存到设备寄存器lamp中去*/ static ssize_t vp_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) { int err = 0; char* page = NULL; if(len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu.\n", len); return -EFAULT; } page = (char*)__get_free_page(GFP_KERNEL); if(!page) { printk(KERN_ALERT"Failed to alloc page.\n"); return -ENOMEM; } /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/ if(copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user.\n"); err = -EFAULT; goto out; } err = __vp_set_lamp(vp_dev, page, len); out: free_page((unsigned long)page); return err; } /*创建/proc/vp文件*/ static void vp_create_proc(void) { struct proc_dir_entry *entry; entry = create_proc_entry(VP_DEVICE_PROC_NAME, 0, NULL); if(entry) { entry->read_proc = vp_proc_read; entry->write_proc = vp_proc_write; } } /*删除/proc/vp文件*/ static void vp_remove_proc(void) { remove_proc_entry(VP_DEVICE_PROC_NAME, NULL); } /******************************************* *define load and remove function *******************************************/ /*初始化设备*/ static int __vp_setup_dev(struct vp_android_dev* dev) { int err; dev_t devno = MKDEV(vp_major, vp_minor); memset(dev, 0, sizeof(struct vp_android_dev)); cdev_init(&(dev->dev), &vp_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &vp_fops; /*注册字符设备*/ err = cdev_add(&(dev->dev),devno, 1); if(err) { return err; } /*初始化信号量和寄存器lamp, val的值*/ sema_init(&(dev->sem), 1); dev->lamp = 7777; dev->val.toggle = 1; dev->val.virtual_latitude = 45.104108; dev->val.virtual_longitude = 130.816878; return 0; } /*模块加载方法*/ static int __init vp_init(void){ int err = -1; dev_t dev = 0; struct device* temp = NULL; printk(KERN_ALERT"Initializing vp device.\n"); /*动态分配主设备和从设备号*/ err = alloc_chrdev_region(&dev, 0, 1, VP_DEVICE_NODE_NAME); if(err < 0) { printk(KERN_ALERT"Failed to alloc char dev region.\n"); goto fail; } vp_major = MAJOR(dev); vp_minor = MINOR(dev); /*分配helo设备结构体变量*/ vp_dev = kmalloc(sizeof(struct vp_android_dev), GFP_KERNEL); if(!vp_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc vp_dev.\n"); goto unregister; } /*初始化设备*/ err = __vp_setup_dev(vp_dev); if(err) { printk(KERN_ALERT"Failed to setup dev: %d.\n", err); goto cleanup; } /*在/sys/class/目录下创建设备类别目录vp*/ vp_class = class_create(THIS_MODULE, VP_DEVICE_CLASS_NAME); if(IS_ERR(vp_class)) { err = PTR_ERR(vp_class); printk(KERN_ALERT"Failed to create vp class.\n"); goto destroy_cdev; } /*在/dev/目录和/sys/class/vp目录下分别创建设备文件vp*/ temp = device_create(vp_class, NULL, dev, "%s", VP_DEVICE_FILE_NAME); if(IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create vp device."); goto destroy_class; } /*在/sys/class/vp/vp目录下创建属性文件val*/ err = device_create_file(temp, &dev_attr_val); if(err < 0) { printk(KERN_ALERT"Failed to create attribute val."); goto destroy_device; } dev_set_drvdata(temp, vp_dev); /*创建/proc/vp文件*/ vp_create_proc(); printk(KERN_ALERT"Succedded to initialize vp device.\n"); return 0; destroy_device: device_destroy(vp_class, dev); destroy_class: class_destroy(vp_class); destroy_cdev: cdev_del(&(vp_dev->dev)); cleanup: kfree(vp_dev); unregister: unregister_chrdev_region(MKDEV(vp_major, vp_minor), 1); fail: return err; } /*模块卸载方法*/ static void __exit vp_exit(void) { dev_t devno = MKDEV(vp_major, vp_minor); printk(KERN_ALERT"Destroy vp device.\n"); /*删除/proc/vp文件*/ vp_remove_proc(); /*销毁设备类别和设备*/ if(vp_class) { device_destroy(vp_class, MKDEV(vp_major, vp_minor)); class_destroy(vp_class); } /*删除字符设备和释放设备内存*/ if(vp_dev) { cdev_del(&(vp_dev->dev)); kfree(vp_dev); } /*释放设备号*/ unregister_chrdev_region(devno, 1); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Virtualposition Driver"); module_init(vp_init); module_exit(vp_exit);
添加 Kconfig 文件config VP tristate "Virtual Position Driver" default n help This is the virtual position driver.
添加 Makefile 文件obj-$(CONFIG_VP) += vp.o
修改 drivers/Kconfig 文件 在menu "Device Drivers"和endmenu之间添加一行:source "drivers/vp/Kconfig"
修改drivers/Makefile文件,添加一行:obj-$(CONFIG_HELLO) += vp/
修改 arch/arm/configs目录下的cyanogen_cancro_defconfig 文件,在文件末尾加入# CONFIG_VP CONFIG_VP=y
=============分割线2==============
第二步,修改HAL
进入 ./hardware/libhardware/include/hardware 目录,新建 vp.h 文件#ifndef ANDROID_VP_INTERFACE_H #define ANDROID_VP_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS /*定义模块ID*/ #define VP_HARDWARE_MODULE_ID "vp" //typedef enum{false, true} bool; /*define virtual position structrue*/ typedef struct { int toggle; double virtual_latitude; double virtual_longitude; } VirtualPosition; /*硬件模块结构体*/ struct vp_module_t { struct hw_module_t common; }; /*硬件接口结构体*/ struct vp_device_t { struct hw_device_t common; int fd; int (*set_val)(struct vp_device_t* dev, VirtualPosition val); int (*get_val)(struct vp_device_t* dev, VirtualPosition* val); }; __END_DECLS #endif
进入到 hardware/libhardware/modules 目录,新建vp目录,并添加vp.c文件#define LOG_TAG "VpStub" #include <hardware/hardware.h> #include <hardware/vp.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #define DEVICE_NAME "/dev/vp" #define MODULE_NAME "Vp" #define MODULE_AUTHOR "aggresss@163.com" /*设备打开和关闭接口*/ static int vp_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device); static int vp_device_close(struct hw_device_t* device); /*设备访问接口*/ static int vp_set_val(struct vp_device_t* dev, VirtualPosition val); static int vp_get_val(struct vp_device_t* dev, VirtualPosition* val); /*模块方法表*/ static struct hw_module_methods_t vp_module_methods = { open: vp_device_open }; /*模块实例变量*/ struct vp_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: VP_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &vp_module_methods, } }; static int vp_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { struct vp_device_t* dev;dev = (struct vp_device_t*)malloc(sizeof(struct vp_device_t)); if(!dev) { ALOGE("Vp Stub: failed to alloc space"); return -EFAULT; } memset(dev, 0, sizeof(struct vp_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (hw_module_t*)module; dev->common.close = vp_device_close; dev->set_val = vp_set_val;dev->get_val = vp_get_val; if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { ALOGE("Vp Stub: failed to open /dev/vp -- %s.", strerror(errno));free(dev); return -EFAULT; } *device = &(dev->common); ALOGI("Vp Stub: open /dev/vp successfully."); return 0; } static int vp_device_close(struct hw_device_t* device) { struct vp_device_t* vp_device = (struct vp_device_t*)device; if(vp_device) { close(vp_device->fd); free(vp_device); } return 0; } static int vp_set_val(struct vp_device_t* dev, VirtualPosition val) { ALOGI("Vp Stub: set value %d to device.", val); write(dev->fd, &val, sizeof(val)); return 0; } static int vp_get_val(struct vp_device_t* dev, VirtualPosition* val) { if(!val) { ALOGE("Vp Stub: error val pointer"); return -EFAULT; } read(dev->fd, val, sizeof(*val)); ALOGI("Vp Stub: get value %d from device", *val); return 0; }
继续在vp目录下新建Android.mk文件:LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := vp.c LOCAL_MODULE := vp.default include $(BUILD_SHARED_LIBRARY)
=============分割线3==============
第三步,修改JNI
进入 frameworks/base/services/core/jni 目录,新建com_android_server_VirtualPositionService.cpp文件#define LOG_TAG "VirtualPositionService" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/vp.h> #include <stdio.h> namespace android { VirtualPosition virtual_position = {1, 0.0, 0.0}; /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/vp.h>*/ struct vp_device_t* vp_device = NULL; /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/ static void vp_setVal() { ALOGI("VirtualPosition JNI: set value to device."); if(!vp_device) { ALOGI("VirtualPosition JNI: device is not open."); return; } vp_device->set_val(vp_device, virtual_position); } /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/ static void vp_getVal() { if(!vp_device) { ALOGI("VirtualPosition JNI: device is not open."); } vp_device->get_val(vp_device, &virtual_position); ALOGI("VirtualPosition JNI: get value from device."); } /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/ static inline int vp_device_open(const hw_module_t* module, struct vp_device_t** device) { return module->methods->open(module, VP_HARDWARE_MODULE_ID, (struct hw_device_t**)device); } /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/ static jboolean vp_init(JNIEnv* env, jclass clazz) { vp_module_t* module; ALOGI("VirtualPosition JNI: initializing......"); if(hw_get_module(VP_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) { ALOGI("VirtualPosition JNI: vp Stub found."); if(vp_device_open(&(module->common), &vp_device) == 0) { ALOGI("VirtualPosition JNI: vp device is open."); return 0; } ALOGE("VirtualPosition JNI: failed to open vp device."); return -1; } ALOGE("VirtualPosition JNI: failed to get vp stub module."); return -1; } static void android_server_VirtualPositionService_set_virtual_toggle(JNIEnv* env, jclass clazz, jint tog) { virtual_position.toggle = tog; vp_setVal(); } static jint android_server_VirtualPositionService_get_virtual_toggle(JNIEnv* env, jclass clazz) { vp_getVal(); return virtual_position.toggle; } static void android_server_VirtualPositionService_set_virtual_latitude(JNIEnv* env, jclass clazz, jdouble vlat) { virtual_position.virtual_latitude = vlat; vp_setVal(); } static jdouble android_server_VirtualPositionService_get_virtual_latitude(JNIEnv* env, jclass clazz) { vp_getVal(); return virtual_position.virtual_latitude; } static void android_server_VirtualPositionService_set_virtual_longitude(JNIEnv* env, jclass clazz, jdouble vlon) { virtual_position.virtual_longitude = vlon; vp_setVal(); } static jdouble android_server_VirtualPositionService_get_virtual_longitude(JNIEnv* env, jclass clazz) { vp_getVal(); return virtual_position.virtual_longitude; } /*JNI方法表*/ static const JNINativeMethod method_table[] = { {"init_native", "()Z", (void*)vp_init}, {"native_set_virtual_toggle", "(I)V", (void*)android_server_VirtualPositionService_set_virtual_toggle}, {"native_get_virtual_toggle", "()I", (void*)android_server_VirtualPositionService_get_virtual_toggle}, {"native_set_virtual_latitude", "(D)V", (void*)android_server_VirtualPositionService_set_virtual_latitude}, {"native_get_virtual_latitude", "()D", (void*)android_server_VirtualPositionService_get_virtual_latitude}, {"native_set_virtual_longitude", "(D)V", (void*)android_server_VirtualPositionService_set_virtual_longitude}, {"native_get_virtual_longitude", "()D", (void*)android_server_VirtualPositionService_get_virtual_longitude}, }; /*注册JNI方法*/ int register_android_server_VirtualPositionService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/VirtualPositionService", method_table, NELEM(method_table)); } };
修改同目录下的onload.cpp文件,首先在namespace android增加com_android_server_VirtualPositionService函数声明:namespace android { .............................................................................................. int register_android_server_VirtualPositionService(JNIEnv *env); }; 在JNI_onLoad增加register_android_server_VirtualPositionService函数调用: extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved) { ................................................................................................. register_android_server_VirtualPositionService(env); ................................................................................................. }
修改同目录下的Android.mk文件,在LOCAL_SRC_FILES变量中增加一行:LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ com_android_server_InputManager.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ com_android_server_UsbService.cpp \ com_android_server_VibratorService.cpp \ com_android_server_location_GpsLocationProvider.cpp \ com_android_server_VirtualPositionService.cpp \ onload.cpp
=============分割线4==============
第四步,修改Framework
进入到frameworks/base/core/java/android/os目录,新增VirtualPositionService.aidl接口定义文件package android.os; interface IVirtualPositionService { void setVirtualToggle(int tog); int getVirtualToggle(); void setVirtualLatitude(double vlat); double getVirtualLatitude(); void setVirtualLongitude(double vlon); double getVirtualLongitude(); }
然后进入 frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IVirtualPosition.aidl源文件:LOCAL_SRC_FILES += / .................................................................... core/java/android/os/IVibratorService.aidl / core/java/android/os/IVirtualPosition.aidl / core/java/android/service/urlrenderer/IUrlRendererService.aidl / .....................................................................
进入到frameworks/base/services/java/com/android/server目录,新增VirtualPositionService.java文件package com.android.server; import android.content.Context; import android.os.IVirtualPositionService; import android.util.Slog; public class VirtualPositionService extends IVirtualPositionService.Stub { private static final String TAG = "VirtualPositionService"; VirtualPositionService() { init_native(); } public void setVirtualToggle(int tog) { native_set_virtual_toggle(tog); } public int getVirtualToggle(){ return native_get_virtual_toggle(); } public void setVirtualLatitude(double vlat) { native_set_virtual_latitude(vlat); } public double getVirtualLatitude(){ return native_get_virtual_latitude(); } public void setVirtualLongitude(double vlon) { native_set_virtual_longitude(vlon); } public double getVirtualLongitude() { return native_get_virtual_longitude(); } private static native boolean init_native(); private static native void native_set_virtual_toggle(int tog); private static native int native_get_virtual_toggle(); private static native void native_set_virtual_latitude(double vlat); private static native double native_get_virtual_latitude(); private static native void native_set_virtual_longitude(double vlon); private static native double native_get_virtual_longitude(); };
修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载VirtualPositionService的代码:@Override public void run() { .................................................................................... try { Slog.i(TAG, "DiskStats Service"); ServiceManager.addService("diskstats", new DiskStatsService(context)); } catch (Throwable e) { Slog.e(TAG, "Failure starting DiskStats Service", e); } try { Slog.i(TAG, "VirtualPosition Service"); ServiceManager.addService("virtualposition", new VirtualPositionService()); } catch (Throwable e) { Slog.e(TAG, "Failure starting VirtualPosition Service", e); } ...................................................................................... }
然后需要修改sepolicy文件,具体的文件在github上,请下载使用。
=============分割线5==============
第五步,修改application
APP的文件比较多,请到github上下载,这里只贴具体的逻辑代码:package com.example.phdemo.myapplication; import android.os.RemoteException; import android.app.Activity; import android.os.ServiceManager; import android.os.Bundle; import android.widget.CompoundButton; import android.os.IVirtualPositionService; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ToggleButton; import android.widget.CompoundButton.OnCheckedChangeListener; public class MainActivity extends Activity implements View.OnClickListener { private final static String LOG_TAG = "com.example.phdemo.virtualposition"; private IVirtualPositionService virtualpositionService = null; private ToggleButton toggleButton = null; private EditText altitudeValueText = null; private EditText longitudeValueText = null; private Button getButton = null; private Button setButton = null; private Button clearButton = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); virtualpositionService = IVirtualPositionService.Stub.asInterface( ServiceManager.getService("virtualposition")); toggleButton=(ToggleButton)findViewById(R.id.toggleButton); altitudeValueText = (EditText)findViewById(R.id.altitude_value); longitudeValueText = (EditText)findViewById(R.id.longitude_value); getButton = (Button)findViewById(R.id.button_get); setButton = (Button)findViewById(R.id.button_set); clearButton = (Button)findViewById(R.id.button_clear); getButton.setOnClickListener(this); setButton.setOnClickListener(this); clearButton.setOnClickListener(this); try{ int val_tog = virtualpositionService.getVirtualToggle(); if(val_tog == 1){ toggleButton.setChecked(true); }else{ toggleButton.setChecked(false); } } catch (Exception e) {} toggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener(){ public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) { toggleButton.setChecked(isChecked); try{ virtualpositionService.setVirtualToggle(isChecked?1:0); }catch(Exception e){} } }); Log.i(LOG_TAG, "VirtualPosition Activity Created"); } @Override public void onClick(View v) { if(v.equals(getButton)) { try { double val_altitude = virtualpositionService.getVirtualLatitude(); String text_altitude = String.valueOf(val_altitude); altitudeValueText.setText(text_altitude); double val_longitude = virtualpositionService.getVirtualLongitude(); String text_longitude = String.valueOf(val_longitude); longitudeValueText.setText(text_longitude); int val_tog = virtualpositionService.getVirtualToggle(); if(val_tog == 1){ toggleButton.setChecked(true); }else{ toggleButton.setChecked(false); } } catch (Exception e) { Log.e(LOG_TAG, "Remote Exception while reading value from GpsLocationProvider."); } } else if(v.equals(setButton)) { try { String text_altitude = altitudeValueText.getText().toString(); String text_longitude = longitudeValueText.getText().toString(); double val_altitude = Double.parseDouble(text_altitude); double val_longitude = Double.parseDouble(text_longitude); virtualpositionService.setVirtualLatitude(val_altitude); virtualpositionService.setVirtualLongitude(val_longitude); } catch (Exception e) { Log.e(LOG_TAG, "Remote Exception while writing value to GpsLocationProvider."); } } else if(v.equals(clearButton)) { String text = ""; altitudeValueText.setText(text); longitudeValueText.setText(text); } } }
=============分割线6==============
最后一步,在JNI层面修改location report 机制。
进入 frameworks/base/services/core/jni 目录,修改com_android_server_location_GpsLocationProvider.cpp文件:
在全局变量部分加入// add by aggresss static int vp_fd = open("/dev/vp", O_RDWR); static VirtualPosition vp_val;
修改location_callback函数:static void location_callback(GpsLocation* location) { JNIEnv* env = AndroidRuntime::getJNIEnv(); //add by aggresss read(vp_fd, &vp_val, sizeof(VirtualPosition)); if(vp_val.toggle == 1){ env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags, (jdouble)vp_val.virtual_latitude, (jdouble)vp_val.virtual_longitude, (jdouble)location->altitude, (jfloat)location->speed, (jfloat)location->bearing, (jfloat)location->accuracy, (jlong)location->timestamp); checkAndClearExceptionFromCallback(env, __FUNCTION__); } else{ env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags, (jdouble)location->latitude, (jdouble)location->longitude, (jdouble)location->altitude, (jfloat)location->speed, (jfloat)location->bearing, (jfloat)location->accuracy, (jlong)location->timestamp); checkAndClearExceptionFromCallback(env, __FUNCTION__); } }
=============我是完成的分割线==============
完成后,重新编译固件,开机后启动VirtualPosition的APP,设置你想要的坐标,想在哪就在哪了。
-
Android 图片属性信息修改(定位信息修改).rar
2019-07-03 20:19:54Android 图片属性信息修改(定位信息修改)无需root 直接获取手机中的图片的信息,并修改 -
[原创] 改机 - 从源码着手任意修改GPS地理位置
2021-05-28 05:59:28改机 - 从源码着手任意修改GPS地理位置需求:随意修改定位android在改机过程中,经常会遇到随意修改位置GPS的需求。修改GPS的方式有很多种:xposed hookMockLocation修改源码以上三种方式都能修改gps随意修改gps坐标...改机 - 从源码着手任意修改GPS地理位置
需求:随意修改定位
android在改机过程中,经常会遇到随意修改位置GPS的需求。
修改GPS的方式有很多种:
xposed hook
MockLocation
修改源码
以上三种方式都能修改gps随意修改gps坐标,各有优缺点:xposed隐藏不好,容易被发现;MockLocation容易在开发者模式和gps provider被识别;改源码,编译麻烦,而且不一定有源码;前两种方式具有普适性,改源码费时费力,局限性比较强;
秉承明知山有虎,偏向虎上行的心态,尝试阅读以下android的源码,并且修改gps部分的代码;
具体原理:切断hal层和framework之间的通讯,模仿硬件向framework通知硬件信息
样例:android 8.0
1. gps jni callbackstruct GnssCallback : public IGnssCallback {
Return gnssLocationCb(
const android::hardware::gnss::V1_0::GnssLocation& location) override; // gps位置变化回调函数
Return gnssStatusCb(const IGnssCallback::GnssStatusValue status) override; // gps状态变化回调函数
Return gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override; // 卫星状态变化回调函数
Return gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
Return gnssSetCapabilitesCb(uint32_t capabilities) override;
Return gnssAcquireWakelockCb() override;
Return gnssReleaseWakelockCb() override;
Return gnssRequestTimeCb() override;
Return gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
static GnssSvInfo sGnssSvList[static_cast(
android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)];
static size_t sGnssSvListSize;
static const char* sNmeaString;
static size_t sNmeaStringLength;
};
// 省略......
Return GnssCallback::gnssLocationCbImpl(const T& location) {
JNIEnv* env = getJniEnv();
jobject jLocation = translateGnssLocation(env, location);
env->CallVoidMethod(mCallbacksObj,
method_reportLocation, // frameworks
boolToJbool(hasLatLong(location)),
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(jLocation);
return Void();
}
// 省略......
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
"(ZLandroid/location/Location;)V");
GnssCallback的作用就是在gps模块位置、状态、精度等信息变化后,通知上层应用的回调函数类。
2. framework
可以发现,在gps硬件模块拿到新的位置时,通知framework调用java的函数是reportLocation, 源码如下:
/*
* @hasLatLong: 地理位置是否合法
* @loction: 地理位置
*/
private void reportLocation(boolean hasLatLong, Location location) {
if (location.hasSpeed()) {
mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
}
if (mItarSpeedLimitExceeded) {
Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
" GPS/GNSS Navigation output blocked.");
mGnssMetrics.logReceivedLocationStatus(false);
return;
}
if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
synchronized (mLocation) {
mLocation = location;
// It would be nice to push the elapsed real-time timestamp
// further down the stack, but this is still useful
mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
mLocation.setExtras(mLocationExtras);
try {
mILocationManager.reportLocation(mLocation, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
}
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
if (hasLatLong) {
if (location.hasAccuracy()) {
mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
}
if (mTimeToFirstFix > 0) {
int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
}
}
mLastFixTime = SystemClock.elapsedRealtime();
// report time to first fix
if (mTimeToFirstFix == 0 && hasLatLong) {
mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
// notify status listeners
mListenerHelper.onFirstFix(mTimeToFirstFix);
}
if (mSingleShot) {
stopNavigating();
}
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
// we want to time out if we do not receive a fix
// within the time out and we are requesting infrequent fixes
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
mAlarmManager.cancel(mTimeoutIntent);
}
// send an intent to notify that the GPS is receiving fixes.
Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
}
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
if (DEBUG) Log.d(TAG, "got fix, hibernating");
hibernate();
}
}
自此,刨除hal层,android系统就获取到了一个地理位置。原理了解后,就可以动手修改源码了。
3. 切断hal层调用
GnssLocationProvider.cpp
#include
// ....... 省略
Return GnssCallback::gnssLocationCbImpl(const T& location) {
// 定义一个系统开关,可以自由控制
char property[PROP_VALUE_MAX];
int len = __system_property_get("gps.location.custom", property);
if(len > 0) {
if(strcmp(property, "1") == 0) return Void();
}
// ...... 省略
}
4. 在framework中添加一个public函数
LocationManager.java
// ...... 省略
public void reportCustomLocation(Location location) {
mService.reportLocation(true, location);
}
5. 编译rommake update-api # 在LocationManager中添加了新的接口
make -j32 # 炫耀一下我32核的的机器
5. 在APK中使用
MainActivity.java
// ...... 省略
Button btn = findViewById(R.id.test_btn);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
Location l = new Location("gps");
l.setLatitude(41.055962);
l.setLongitude(110.307711);
l.setAccuracy(2.0f);
l.setTime(System.currentTimeMillis());
l.setElapsedRealtimeNanos(System.currentTimeMillis());
l.setAccuracy(1.0f);
locationManager.reportCustomLocation(l);
Location lo = locationManager.getLastKnownLocation(provider);
Log.d(TAG, lo.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
最后于 2020-6-29 11:04
被neocanable编辑
,原因: markdown 好像不太好用
-
Android 定位系统(GPS)开发详解
2021-01-04 18:20:56Android支持地理定位服务的API。该地理定位服务可以用来获取当前设备的地理位置,应用程序可以定时请求更新设备当前的地理位置信息。比如应用程序可以借助一个Intent接收器来实现如下功能: 以经纬度和半径规划一个... -
Android实现地理定位功能
2021-05-27 00:54:32最近试着写了一下Android的定位,代码在下面,比较简单首先需要的权限有然后是里面的代码package com.example.a5.myapplication;import android.Manifest;import android.content.Context;import android.content.pm...最近试着写了一下Android的定位,代码在下面,比较简单
首先需要的权限有
然后是里面的代码
package com.example.a5.myapplication;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取位置服务
LocationManager locationManager = (LocationManager) MainActivity.this.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
//ACCURACY_HIGH/ACCURACY_LOW精度选择
criteria.setAccuracy(Criteria.ACCURACY_FINE);
//高度
criteria.setAltitudeRequired(true);
//方位信息
criteria.setBearingRequired(true);
//是否允许付费
criteria.setCostAllowed(true);
//对电量的要求
criteria.setPowerRequirement(Criteria.POWER_LOW);
//速度
criteria.setSpeedRequired(true);
//获取最佳服务
String provider = locationManager.getBestProvider(criteria, true);
//权限检查
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
//获取到了位置
Location location = locationManager.getLastKnownLocation(provider);
//开启地理位置监听定位类型、毫秒、米、监听时间
locationManager.requestLocationUpdates(provider,3000,1,new listener());
locateResult(location);
}
});
}
public class listener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
//位置变化,获取最新的位置
locateResult(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
public void locateResult(Location location){
new AlertDialog.Builder(MainActivity.this)
.setMessage("纬度" + String.valueOf(location.getLatitude()) +
"\n经度" + String.valueOf(location.getLongitude()) +
"\n速度" + String.valueOf(location.getSpeed()) +
"\n高度" + String.valueOf(location.getAltitude()) +
"\n朝向" + String.valueOf(location.getBearing())
)
.setNegativeButton("取消",null)
.show();
}
}
最后上图:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
-
修改安卓定位服务器地址
2021-08-14 05:25:23修改安卓定位服务器地址 内容精选换一换安卓模拟器(Android Virtual Device),简称AVD,可以模拟安卓设备并将其运行在服务器上。利用AVD,您可以对安卓应用进行原型设计、开发和测试,而无需使用真实的手机。AVD具备... -
Android中Xposed框架篇---修改系统位置信息实现自身隐藏功能
2018-03-29 09:18:09在Android中关于这几种定位都有具体的调用方法,所以如果想修改系统的定位信息,那么就必须先了解这几种调用方式,在之前的一篇文章中也说到了,Hook的最关键一点就是需要找到Hook的地方,这个就需要去阅读源码来... -
OTGLocation:使用Android设备修改iPhone位置
2021-03-04 01:46:25该项目基于开源库开发,并认识到Android设备OTG在连接到iPhone后可以修改iPhone的经度和纬度。 如果需要将可执行文件和库文件从开源项目移植到Android平台,则可以转到进行查看。 我整理了一些 感谢在开源项目问题... -
Android仿京东地址选择-修改
2018-09-30 11:47:27修改版---仿京东地址选择器一比一复刻,原理:viewpager+tablayout+view -
[原创]修改源码实现全局(无需root)注入躲开注入检测
2021-06-03 13:22:47会编译android源码(如果你不愿意编译源码,还有另外一种办法,下面我会提供)2.会使用substrate或者xposed以上2个网上资料很多我就不啰嗦了一、市面上目前的hook和注入工具市面上目前的hook有substrate,xposed,或者... -
修改系统型号版本imei,以及手机定位
2018-06-07 13:33:49了解xposed框架,安装xposed框架并激活,打开此软件,设置想要修改的信息,然后选择应用,在xposed框架勾选,重启生效 -
Android开发使用LocationManager实现定位服务
2019-11-09 23:06:40gps定位,实测可用. 第一个是网络定位,第二个是GPS定位,第三个是直接取缓存。LocationManager本身提供了选择最好的provider的方法: // 获取最好的定位方式 String provider = locationManager.... -
android 模拟定位app 源码
2021-06-07 12:43:38【实例简介】需要在android手机的 开发者模式中 开启 【允许模拟位置】即可,开启允许模拟位置的方法详见:...import android.app.Activity;import android... -
android室内定位demo
2014-09-10 10:30:12根据室内多个wifi信号的强度进行定位; 可以扫描室内wifi的型号强度Value,并记录到数据库。 目前还未完善:需要手动修改代码将记录的数据写入定位代码。 但大体定位能够成功,概率90%准确定位率; 基本算法已经可以... -
改变GPS定位实现Android模拟定位的方法
2021-05-28 01:24:34改变GPS定位实现Android模拟定位的方法,最近需要对微信,陌陌等程序进行位置模拟 实现世界各地发朋友圈,搜索附近人的功能,本着站在巨人肩膀上的原则 爱网上搜索一番,也找到一些 代码和文章,但是代码大都雷同... -
【Android系统源码修改】修改系统默认定位方式
2019-07-14 09:08:48gps 移动网络位置信息 ...\frameworks\base\services\core\java\com\android\server\location\GpsLocationProvider.java ro.wisky.gpssupport 此值设为 false 时不支持,则系统中一些有关 gps 的设置将会被... -
android 免 root修改位置打卡
2019-09-21 13:12:32Virtual Xponse(一个 类似于 android 虚拟机的东西, 可以将 android 软件 安装到里面, 或者也可以使用一些 xponse插件, ) 修改gps定位的软件。 你需要打卡的软件 将 修改 gps的软件, 与需要打卡的软件都安装在 ... -
免root实现 Android改机(一键新机)技术解密。
2021-01-20 08:48:09Android_Id、IMEI、手机序列号、手机号码、WIFI-MAC、WIFI-Name、安卓系统版本、ROM固件、手机号码、手机型号、手机品牌、CPU型号、手机制造商、GPS定位、通话记录模拟、手机短信模拟…… 等各类安卓手机系统信息的... -
安卓定位方式全总结-gps定位,network定位,ip定位,基站定位
2021-06-02 21:27:08一般我们使用的是第三...文章目录定位方式1.gps和network(时效性差)1.1 使用条件1.1.1 需要开启位置服务:1.1.2 安卓6.0以上还需要开启位置权限android.permission.ACCESS_COARSE_LOCATION,android.permission.ACC... -
使用Android设备修改iPhone位置-Android开发
2021-05-26 12:18:26该项目基于libimobiledevice开源库开发,并意识到Android设备OTG在连接到iPhone OTG之后可以修改iPhone的经度和纬度。该项目基于libimobiledevice开源库开发,并意识到连接到iPhone后,Android设备OTG可以修改iPhone... -
解决Android 10/Android Q手机在后台无法正常定位问题
2021-01-04 10:03:18Android 10 在2019年9月份正式发布,带来了一个非常重大的GPS权限改变。为用户提供了 仅在使用此应用时允许。一旦用户选择“仅在使用此应用时允许”,就会导致APP在后台或者锁屏时候无法正常记录GPS轨迹,这个对像... -
uniapp 定位 android ios
2021-09-02 15:00:01uniapp 定位 android ios <view class="cen-style"> <view class="cens-title">详细地址:</view> <view class="fbc"> <view style="width: 400rpx;"><u-input v-... -
android模拟位置(修改)
2014-12-11 22:38:21开启手机的模拟位置,获取位置和外网ip,并改变当前的手机经纬度,显示在界面中。在界面中绑定服务,在服务线程中不断的刷新修改的位置信息。 -
安卓joy定位
2019-02-21 13:39:22gpsjoystick安卓定位模拟可以打开隐私模式通过开启开发者权限 -
【Android 逆向】Android 逆向基本概念 ( 定位内存中的修改点 | 基址寻址法 | 搜索定位法 )
2021-10-05 22:56:26一、定位内存中的修改点、 1、基址寻址法、 2、搜索定位法、 -
安卓含定位天气预报实现
2018-05-30 14:29:30项目使用了www.webxml.com.cn网站上的天气预报服务,需要把代码中的useid修改为自己的,另外项目使用了百度API实现了定位。 -
Android定位功能实现
2020-05-28 18:20:10关于Android定位功能如何实现的文章实在太多,有些文章着重于Android API的用法,有些则没有整个定位实现的完整流程,有些虽然有流程,但当你按照文章中的步骤实现好之后,很可能会发现各种问题,最常见的问题就是拿...