0

我写了一个安卓应用。导出为通过安装到设备的邮件发送的签名 APK。- 不在市场上。

在运行时,它将使用类似的代码将它们的数据保存到内部存储中:

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

据我所知 - 如果我错了,请纠正我 - 它已保存到 /data/data/com.mycompany.myapp/FILENAME

因为它被保存了MODE_PRIVATE我不确定市场或我的任何其他应用程序是否可以看到它保存它。也许如果我创建一个具有相同签名的应用程序?

手机没有root。我尝试了很多备份,使用应用程序和 ADB shell 进行复制。应用程序没有保存我的文件,adb shell 授予权限被拒绝。

是否有任何编程解决方案或不获取该文件?

4

1 回答 1

0

我写了一个小代码部分来测试它:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

    private EditText tfData;
    private Button btSave, btLoad;

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

        tfData = (EditText) findViewById(R.id.tfData);
        btSave = (Button) findViewById(R.id.btSave);
        btLoad = (Button) findViewById(R.id.btLoad);

        btSave.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                doSave();
            }
        });

        btLoad.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                doLoad();
            }
        });
        tfData.setText("Some secret data");

        boolean btLoadVisible = false; // TODO change this value for the second build!

        if (!btLoadVisible) {
            btLoad.setVisibility(View.GONE);
        }
        else{
            btSave.setVisibility(View.INVISIBLE);
        }

    }

    private static final String FILENAME = "private.dat";

    private void doSave() {
        String text = null;
        if (tfData.getText() == null) {
            Toast.makeText(this, "Please enter a string!", Toast.LENGTH_SHORT).show();
            return;
        }
        text = tfData.getText().toString();

        if (text == null || text.length() == 0) {
            Toast.makeText(this, "Please enter a string!!!", Toast.LENGTH_SHORT).show();
        }

        FileOutputStream fos = null;
        try {
            fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
            fos.write(text.getBytes("UTF-8"));
            fos.close();
            fos = null;
            
            new AlertDialog.Builder(this).setTitle("Saved").setMessage("Your data is saved:\n" + text+"\nChange the build to recover it!")
            .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            }).show();
            
        } catch (Exception e) {
            Log.e("doSave", "Can't save ...", e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    // I don't care:
                    e.printStackTrace();
                }
            }
        }

    }

    private void doLoad() {
        FileInputStream fis = null;
        try {
            fis = openFileInput(FILENAME);
        } catch (FileNotFoundException e) {
            e.printStackTrace();

            new AlertDialog.Builder(this)
                    .setTitle("FileNotFoundException")
                    .setMessage(
                            "The file with data can't be found. Or it wasn't saved at all or you have uninstalled the old app or... who knows.\nI can't recover the data, it is lost permanenty!!!")
                    .setPositiveButton("I am sad", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).show();
            return; // I don't like return from catch...
        }

        if (fis != null) {

            try {
                int size = fis.available();// not the best, but now I hope is possible to read 10-30 bytes without blocking
                byte[] buff = new byte[size];
                int readCount = fis.read(buff);
                if (readCount != size) {
                    Toast.makeText(this, "Dammit can't read : " + size + " bytes, only " + readCount + ". Restart app, than phone? ", Toast.LENGTH_SHORT)
                            .show();
                }
                String text = new String(buff, "UTF-8");
                tfData.setText(text);

                new AlertDialog.Builder(this).setTitle("Loaded").setMessage("Your data is recovered:\n" + text)
                        .setPositiveButton("I am happy", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        }).show();

            } catch (IOException e) {

                Log.e("doLoad", "Can't load ...", e);

                new AlertDialog.Builder(this).setTitle("IOException").setMessage("There is some error while reading the data:\n" + e.getMessage())
                        .setPositiveButton("I am sad", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        }).show();

            }
        }
    }

}

清理、构建、导出为签名的 apk:例如 InternalMemoryReader_save.apk

在此处输入图像描述

保存密钥库!!!

  • 更改boolean btLoadVisible = falseboolean btLoadVisible = true.
  • 使用相同的密钥库导出 apk!但名称不同,例如 InternalMemoryReader_load.apk - 但可以是 _datasaver _factoryservice 什么的。这通常不会提供给用户。

在此处输入图像描述

安装第一个 apk 并保存。

  • 不要卸载apk

  • 让我们建议您责备数据丢失,无法打开它......一旦在邮件中,您将收到来自支持服务的 _load.apk。安装它而不删除旧的 apk。它具有相同的包名,相同的签名,只是不同的文件名。

    我能够加载数据。它可以通过邮件发送或在那里处理,最难的部分已经完成。

结论:

如果您是应用程序开发人员,并且您拥有密钥库并且能够签署修改后的 apk,那么您将可以访问该内部私有文件。

我希望我正在帮助其他人恢复他的应用程序数据,而不是浪费太多时间。

如果您知道更好的解决方案,请告诉我!

于 2013-11-07T00:47:53.233 回答