从内部存储恢复数据

时间:2013-11-06 18:50:18

标签: android data-recovery internal-storage

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

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

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

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

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

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

有没有编程的解决方案或不获取该文件?

1 个答案:

答案 0 :(得分: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

enter image description here

保存密钥库!!!

  • boolean btLoadVisible = false更改为boolean btLoadVisible = true
  • 导出apk与同一个KEYSTORE!但是diff名称,例如InternalMemoryReader_load.apk - 但可以是_datasaver _factoryservice。这通常不会给用户。

enter image description here

安装第一个apk并进行保存。

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

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

<强>结论:

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

我希望我能帮助其他人恢复他的应用数据而不是浪费那么多时间。

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