刚学习不久,正好最近遇到一个问题,拿来练练手
起因
最近使用某阅读应用看书,app 的阅读体验并不好,所以想要找到下载的文件导入到其他阅读器阅读,但是常规方法并没有找到,所以反编译看下下载位置。
准备
工具:jadx, DB Browser;
一部有 root 权限的手机;
查找过程
-
首先读取包名:cn.com.bookan
-
adb shell dumpsys window 获取书刊阅读的界面类名是 EpubReaderActivity
-
在阅读页面下方有下载按钮,点击下载后,会有一个提示:下载中,请到“书架”-“我的下载”中查看", 在 EpubReaderActivity 中搜索提示的字符串,可以找到下载按钮的点击逻辑:
/* access modifiers changed from: package-private */
@OnClick({2131296832})
public void onDownloadClick(View view) {
LogUtil.m15486a(this.f8694j, 20007, 3);
if (!NetUtil.m15279a(this)) {
MyToast.m16477a(this, getString(C1300R.string.net_error), 0).show();
} else if (FusionField.m13348ac() > 0 || DBScanRecord.m13484a().mo19549a(this.f8694j)) {
new CountDownTimer(1000, 200) {
public void onFinish() {
if (FusionField.f10257s == 1) {
DBDownload.m13459a().mo19524b(EpubReaderActivity.this.f8694j, "epub");
DBDownload.m13459a().mo19522a(GsonUtil.m15346a(EpubReaderActivity.this.f8694j), 100, EpubReaderActivity.this.f8694j, "epub");
} else {
DBDownload.m13459a().mo19521a(EpubReaderActivity.this.f8694j, "epub");
DBDownload.m13459a().mo19525b(GsonUtil.m15346a(EpubReaderActivity.this.f8694j), 100, EpubReaderActivity.this.f8694j, "epub");
}
EpubReaderActivity.this.itemReaderBotomOpdoneContainer.setVisibility(0);
EpubReaderActivity.this.itemReaderBotomOpopContainer.setVisibility(8);
}
public void onTick(long j) {
int unused = EpubReaderActivity.this.f8678ab = EpubReaderActivity.this.f8678ab + 20;
EpubReaderActivity.this.itemReaderBottomDownloadText.setText(EpubReaderActivity.this.getString(C1300R.string.reader_download_ing));
EpubReaderActivity.this.itemReaderBottomDownloadImg.setImageResource(C1300R.C1301drawable.btn_download_resume);
EpubReaderActivity.this.itemReaderBottomDownloadProgress.setVisibility(0);
EpubReaderActivity.this.itemReaderBottomDownloadProgress.setProgress(EpubReaderActivity.this.f8678ab);
}
}.start();
Toast.makeText(this, "下载中,请到“书架”-“我的下载”中查看", 0).show();
} else {
new MyDialogNotice(this, String.format(getString(C1300R.string.right_download), new Object[]{FusionField.m13362aq(), FusionField.m13363ar()})).show();
}
}
可以发现应该是这块逻辑做的下载操作:
if (FusionField.f10257s == 1) {
DBDownload.m13459a().mo19524b(EpubReaderActivity.this.f8694j, "epub");
DBDownload.m13459a().mo19522a(GsonUtil.m15346a(EpubReaderActivity.this.f8694j), 100, EpubReaderActivity.this.f8694j, "epub");
} else {
DBDownload.m13459a().mo19521a(EpubReaderActivity.this.f8694j, "epub");
DBDownload.m13459a().mo19525b(GsonUtil.m15346a(EpubReaderActivity.this.f8694j), 100, EpubReaderActivity.this.f8694j, "epub");
}
虽然混淆了,但是下载应该是通过 mo19522a 或 mo19525b 方法,跟进去看下:
理解错了,这俩应该是线程操作:
/* renamed from: b */
public void mo19525b(String str, int i, IssueInfo issueInfo, String str2) {
ThreadPoolUtil.m15065a().mo21766a((Runnable) new C3138c(str, i, issueInfo, str2));
ThreadPoolUtil.m15065a().mo21767b();
}
不过在它上面正好有 run 方法:
public void run() {
if (StringUtil.m15053c(this.f10398b)) {
Debug.m15248e("DBDownloadinsert mcontent is null", new Object[0]);
return;
}
SQLiteDatabase writableDatabase = MagookDBHelper.m13490a().getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("content", this.f10398b);
contentValues.put(NotificationCompat.CATEGORY_PROGRESS, Integer.valueOf(this.f10399c));
contentValues.put("userid", String.valueOf(FusionField.m13414m()));
contentValues.put("issueid", this.f10400d.getResourceType() == 5 ? this.f10400d.getResourceId() : this.f10400d.getIssueId());
contentValues.put("personid", Integer.valueOf(FusionField.m13320P()));
contentValues.put("readtype", this.f10401e);
long insert = writableDatabase.insert(MagookDBHelper.C3166i.f10503a, (String) null, contentValues);
Debug.m15248e("progress DB: " + this.f10399c, new Object[0]);
Debug.m15244a("DBDownload insert result=%s content=%s", Long.valueOf(insert), this.f10398b);
DownloadItemModel downloadItemModel = new DownloadItemModel();
downloadItemModel.setItem((IssueInfo) GsonUtil.m15344a(this.f10398b, IssueInfo.class));
downloadItemModel.setProgress(this.f10399c);
downloadItemModel.setReadType(this.f10401e);
if (!FusionField.f10261w.containsKey(this.f10400d.getResourceType() == 5 ? this.f10400d.getResourceId() : this.f10400d.getIssueId())) {
FusionField.f10261w.put(this.f10400d.getResourceType() == 5 ? this.f10400d.getResourceId() : this.f10400d.getIssueId(), downloadItemModel);
PreferenceUtil.m14946a("isSynchDownload", true);
}
}
}
看到这里可以确定是存到 SQLITE 中了:
SQLiteDatabase writableDatabase = MagookDBHelper.m13490a().getWritableDatabase();
进 MagookDBHelper 看下:
public void onCreate(SQLiteDatabase sQLiteDatabase) {
sQLiteDatabase.execSQL("CREATE TABLE IF NOT EXISTS download(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,progress INTEGER,userid INTEGER,content TEXT,readtype TEXT)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS readrecord(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,userid INTEGER,content TEXT)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS collection(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,userid INTEGER,content TEXT)");
sQLiteDatabase.execSQL("CREATE TABLE IF NOT EXISTS downloadsingleperson(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,progress INTEGER,userid INTEGER,personid INTEGER,content TEXT,readtype TEXT)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS readrecordsingleperson(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,userid INTEGER,personid INTEGER,content TEXT)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS collectionsingleperson(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,userid INTEGER,personid INTEGER,content TEXT)");
Debug.m15248e("Error inserting: createSQL: " + "create table IF NOT EXISTS message(_id INTEGER PRIMARY KEY AUTOINCREMENT, messageid INTEGER,status INTEGER,type INTEGER,isdelete INTEGER,title VARCHAR(256),url TEXT,content TEXT,resources TEXT,creattime VARCHAR(32))", new Object[0]);
sQLiteDatabase.execSQL("create table IF NOT EXISTS message(_id INTEGER PRIMARY KEY AUTOINCREMENT, messageid INTEGER,status INTEGER,type INTEGER,isdelete INTEGER,title VARCHAR(256),url TEXT,content TEXT,resources TEXT,creattime VARCHAR(32))");
sQLiteDatabase.execSQL("create table IF NOT EXISTS searchhistory(_id INTEGER PRIMARY KEY AUTOINCREMENT,userid INTEGER,restype INTEGER,resourcetype INTEGER,searchtype INTEGER,content TEXT)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS readpositionrecord(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,page INTEGER,userid INTEGER)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS audiopositionrecord(_id INTEGER PRIMARY KEY AUTOINCREMENT, issueid INTEGER,resourceid INTEGER,position INTEGER,userid INTEGER,personid INTEGER,playissueid INTEGER)");
sQLiteDatabase.execSQL("create table IF NOT EXISTS scanrecord(_id INTEGER PRIMARY KEY AUTOINCREMENT, resourceType INTEGER,resourceid INTEGER,issueid)");
}
看不出来放在哪个表了,去手机中 把 DB 拖出来看下:
adb pull /data/data/cn.com.bookan/databases/ .
注意:这个命令需要 root 权限。
看着 books.db 比较像,就是体积有点小,使用 DB Browser 打开看下:
猜测 Files 里面可能有想要的东西,切换到 浏览数据,过滤 Files:
看到一个存储路径 /storage/emulated/0/.bookan/file/487514
把这个文件取下来,放到手机里打开,确实就是刚才下载的文件。
至此,找到了这个 apk 下载的文件位置:
/storage/emulated/0/.bookan/file