From b29c6d77a300eac73ca04aa1e78edeb442247e78 Mon Sep 17 00:00:00 2001 From: dxl <64101226@qq.com> Date: Fri, 22 May 2020 15:10:09 +0800 Subject: [PATCH] 1. PM3 flasher gui add. (on tools) 2. dump merge bug fixed. --- app_main/build.gradle | 4 +- .../main/PM3FlasherMainActivity.java | 7 - .../tools/Proxmark3FirmwareActivity.java | 317 +++++++++++++++++- .../fragment/tools/MainSettingsFragment.java | 11 +- .../fragment/tools/ToolsAccessFragment.java | 11 +- .../main/java/cn/rrg/rdv/util/Commons.java | 7 + .../main/java/cn/rrg/rdv/util/DumpUtils.java | 22 +- .../src/main/res/layout/act_common_tools.xml | 14 + .../res/layout/act_pm3_custom_flasher.xml | 209 +++++++++++- app_main/src/main/res/values-en/strings.xml | 13 + app_main/src/main/res/values-zh/strings.xml | 13 + app_main/src/main/res/values/strings.xml | 13 + pm3rdv4rrg/src/main/cpp/proxmark3 | 2 +- .../java/cn/dxl/common/util/FileUtils.java | 142 ++++---- 14 files changed, 690 insertions(+), 95 deletions(-) diff --git a/app_main/build.gradle b/app_main/build.gradle index 05e594fc..5b9d1c25 100644 --- a/app_main/build.gradle +++ b/app_main/build.gradle @@ -8,8 +8,8 @@ android { minSdkVersion 19 targetSdkVersion 29 testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - versionCode 15 - versionName "1.4.2" + versionCode 20 + versionName "1.4.4" } buildTypes { release { diff --git a/app_main/src/main/java/cn/rrg/rdv/activities/main/PM3FlasherMainActivity.java b/app_main/src/main/java/cn/rrg/rdv/activities/main/PM3FlasherMainActivity.java index 6fd9863e..30900eb6 100644 --- a/app_main/src/main/java/cn/rrg/rdv/activities/main/PM3FlasherMainActivity.java +++ b/app_main/src/main/java/cn/rrg/rdv/activities/main/PM3FlasherMainActivity.java @@ -180,11 +180,4 @@ public class PM3FlasherMainActivity extends BaseActivity implements DevCallback< public void onDetach(String dev) { } - - @Override - public boolean onTouchEvent(MotionEvent event) { - // LogUtils.d("X: " + event.getRawX()); - // LogUtils.d("Y: " + event.getRawY()); - return super.onTouchEvent(event); - } } diff --git a/app_main/src/main/java/cn/rrg/rdv/activities/tools/Proxmark3FirmwareActivity.java b/app_main/src/main/java/cn/rrg/rdv/activities/tools/Proxmark3FirmwareActivity.java index ecbc5570..46694b6c 100644 --- a/app_main/src/main/java/cn/rrg/rdv/activities/tools/Proxmark3FirmwareActivity.java +++ b/app_main/src/main/java/cn/rrg/rdv/activities/tools/Proxmark3FirmwareActivity.java @@ -1,12 +1,34 @@ package cn.rrg.rdv.activities.tools; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; import androidx.annotation.Nullable; +import com.iobridges.com.LocalComBridgeAdapter; +import com.proxgrind.pm3flasher.Proxmark3Flasher; +import com.proxgrind.pm3flasher.Target; + +import java.io.File; + +import cn.dxl.common.util.FileUtils; +import cn.dxl.common.widget.ToastUtil; import cn.dxl.mifare.NfcTagListenUtils; +import cn.proxgrind.com.DevCallback; +import cn.proxgrind.com.UsbSerialControl; import cn.rrg.rdv.R; import cn.rrg.rdv.activities.main.BaseActivity; +import cn.rrg.rdv.util.Commons; +import cn.rrg.rdv.util.Paths; +import cn.rrg.rdv.widget.MaterialAlertDialog; +import cn.rrg.rdv.widget.ProDialog1; /** * Provide users with an interactive PM3 firmware upgrade interface. @@ -16,7 +38,41 @@ import cn.rrg.rdv.activities.main.BaseActivity; * @author DXL * @version 1.0 */ -public class Proxmark3FirmwareActivity extends BaseActivity { +public class Proxmark3FirmwareActivity extends BaseActivity implements DevCallback { + + private TextView txtShowClientVersion; + + private RadioGroup rdoGroupImageSource; + private RadioButton rdoBtnFromApp; + private RadioButton rdoBtnFromUser; + + private EditText edtShowBootRomName; + private EditText edtShowFullImageName; + + private Button btnSelectBootRom; + private Button btnSelectFullImage; + + private Button btnFlash; + + private View layout_image_select; + + private enum MODE { + BOOT, OS + } + + private MODE selectImage = MODE.BOOT; + private MODE flashImage = MODE.BOOT; + + private UsbSerialControl control = UsbSerialControl.get(); + private Proxmark3Flasher flasher = Proxmark3Flasher.getFlasher(); + + private ProDialog1 proDialog1; + + private boolean isFlashing = false; + + // The image path for bt & fi. + private String bootRomImagePath; + private String fullImagePath; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -24,11 +80,270 @@ public class Proxmark3FirmwareActivity extends BaseActivity { setContentView(R.layout.act_pm3_custom_flasher); NfcTagListenUtils.removeListener(this); + // init and try to connect. + control.register(this); + + // start communication forward! + LocalComBridgeAdapter.getInstance() + .startServer(LocalComBridgeAdapter.NAMESPACE_DEFAULT); + + proDialog1 = new ProDialog1(context); + + initViews(); + initActions(); + } + + private void initViews() { + txtShowClientVersion = findViewById(R.id.txtShowClientVersion); + txtShowClientVersion.setText(Commons.PM3_CLIENT_VERSION); + + rdoGroupImageSource = findViewById(R.id.rdoGroupImageSource); + rdoBtnFromApp = findViewById(R.id.rdoBtnFromApp); + rdoBtnFromUser = findViewById(R.id.rdoBtnFromUser); + + edtShowBootRomName = findViewById(R.id.edtShowBootRomName); + edtShowFullImageName = findViewById(R.id.edtShowFullImageName); + + btnSelectBootRom = findViewById(R.id.btnSelectBootRom); + btnSelectFullImage = findViewById(R.id.btnSelectFullImage); + + btnFlash = findViewById(R.id.btnFlash); + + layout_image_select = findViewById(R.id.layout_image_select); + } + + private void initActions() { + btnFlash.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (rdoGroupImageSource.getCheckedRadioButtonId() == R.id.rdoBtnFromApp) { + flashImage = MODE.BOOT; + // init path + bootRomImagePath = Paths.PM3_IMAGE_BOOT_FILE; + fullImagePath = Paths.PM3_IMAGE_OS_FILE; + // init status + isFlashing = true; + connectAndFlash(); + } else { + bootRomImagePath = edtShowBootRomName.getText().toString(); + fullImagePath = edtShowFullImageName.getText().toString(); + if (bootRomImagePath.length() > 0 || fullImagePath.length() > 0) { + // init status + isFlashing = true; + if (bootRomImagePath.length() <= 0) { + flashImage = MODE.OS; + } else { + flashImage = MODE.BOOT; + } + connectAndFlash(); + } else { + new MaterialAlertDialog.Builder(context) + .setMessage(getString(R.string.tips_image_select_bt_fi)) + .show(); + } + } + } + }); + + btnSelectBootRom.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + selectImage = MODE.BOOT; + selectImage(); + } + }); + + btnSelectFullImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + selectImage = MODE.OS; + selectImage(); + } + }); + + rdoGroupImageSource.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + switch (checkedId) { + case R.id.rdoBtnFromApp: + layout_image_select.setVisibility(View.GONE); + break; + case R.id.rdoBtnFromUser: + layout_image_select.setVisibility(View.VISIBLE); + break; + } + } + }); + rdoGroupImageSource.check(R.id.rdoBtnFromApp); + } + + private void selectImage() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + startActivityForResult(intent, 0x77); + } + + private void connectAndFlash() { + // connect device + if (control.connect(null)) { + LocalComBridgeAdapter.getInstance() + .setInputStream(control.getInput()) + .setOutputStream(control.getOutput()); + flashDefaultFW(); + } else { + ToastUtil.show(context, getString(R.string.tips_device_no_found), false); + isFlashing = false; + } + } + + private void flashDefaultFW() { + if (!proDialog1.isShowing()) + proDialog1.show(); + new Thread(new Runnable() { + @Override + public void run() { + if (!flasher.isStart(Target.CLIENT)) { + if (!flasher.start(Target.CLIENT)) { + ToastUtil.show(context, "Client open failed!", false); + proDialog1.dismiss(); + return; + } + } + // 如果没有在Bootloader模式下,我们需要先重启设备使其进入Bootloader模式下! + if (flasher.isStart(Target.BOOT)) { + switch (flashImage) { + case BOOT: + if (bootRomImagePath != null && FileUtils.isFile(bootRomImagePath)) { + if (flasher.flashBootRom(bootRomImagePath)) { + ToastUtil.show(context, getString(R.string.tips_boot_flash_success), false); + } else { + ToastUtil.show(context, getString(R.string.tips_boot_flash_failed), false); + } + finishFlash(); + if (fullImagePath != null && FileUtils.isFile(fullImagePath)) { + // 开启下一轮! + flashImage = MODE.OS; + proDialog1.setTips(getString(R.string.tips_bootrom_flash_finish)); + } else { + isFlashing = false; + proDialog1.dismiss(); + runOnUiThread(new Runnable() { + @Override + public void run() { + new MaterialAlertDialog.Builder(context) + .setMessage(getString(R.string.tips_bootrom_flash_successfully)) + .show(); + } + }); + } + } + break; + + case OS: + if (fullImagePath != null && FileUtils.isFile(fullImagePath)) { + proDialog1.setTips(getString(R.string.tips_fullimage_flashing)); + String msg; + if (flasher.flashFullImg(fullImagePath)) { + msg = getString(R.string.tips_os_flash_success); + } else { + msg = getString(R.string.tips_os_flash_failed); + } + finishFlash(); + isFlashing = false; + proDialog1.dismiss(); + runOnUiThread(new Runnable() { + @Override + public void run() { + new MaterialAlertDialog.Builder(context) + .setMessage(msg) + .show(); + } + }); + } + break; + } + } else { + if (!flasher.start(Target.BOOT)) { + ToastUtil.show(context, getString(R.string.tips_pm3_enter_failed), false); + proDialog1.dismiss(); + isFlashing = false; + } + // 记得关闭客户端 + flasher.close(Target.CLIENT); + } + } + }).start(); + } + + private void finishFlash() { + flasher.close(Target.BOOT); + flasher.close(Target.CLIENT); + } + + private void closeClient() { + new Thread(new Runnable() { + @Override + public void run() { + flasher.close(Target.CLIENT); + } + }).start(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == 0x77) { + if (data != null) { + Uri uri = data.getData(); + String name = FileUtils.getFileNameByUri(context, uri, false); + if (resultCode == RESULT_OK) { + // create a temp file. + File tmpImage = Commons.createTmpFile(name); + // copy content to temp file + FileUtils.copy(uri, tmpImage); + // set path to view! + if (selectImage == MODE.BOOT) { + edtShowBootRomName.setText(tmpImage.getPath()); + } else { + edtShowFullImageName.setText(tmpImage.getPath()); + } + } + if (resultCode == RESULT_CANCELED) { + ToastUtil.show(context, getString(R.string.cancel), false); + } + } + } + } + + @Override + public void onAttach(String dev) { + // 自动连接设备! + if (control.connect(dev)) { + // 更新流引用! + LocalComBridgeAdapter.getInstance() + .setInputStream(control.getInput()) + .setOutputStream(control.getOutput()); + if (isFlashing) { + flashDefaultFW(); + } + } else { + ToastUtil.show(context, "Device connect failed!", false); + } + } + + @Override + public void onDetach(String dev) { } @Override protected void onDestroy() { super.onDestroy(); + proDialog1.dismiss(); + control.unregister(); + closeClient(); + LocalComBridgeAdapter.getInstance() + .stopClient(); } } \ No newline at end of file diff --git a/app_main/src/main/java/cn/rrg/rdv/fragment/tools/MainSettingsFragment.java b/app_main/src/main/java/cn/rrg/rdv/fragment/tools/MainSettingsFragment.java index 807be80f..6efdcc29 100644 --- a/app_main/src/main/java/cn/rrg/rdv/fragment/tools/MainSettingsFragment.java +++ b/app_main/src/main/java/cn/rrg/rdv/fragment/tools/MainSettingsFragment.java @@ -116,7 +116,7 @@ public class MainSettingsFragment ItemTextBean pm3Res = new ItemTextBean(getString(R.string.title_pm3_res_init)) { @Override public void onClick(View view, int pos) { - pm3ResInit(); + pm3ResInit(this); } }; pm3Res.setSubTitle(getString(R.string.title_pm3_res_sub_title)); @@ -160,7 +160,7 @@ public class MainSettingsFragment } } - private void pm3ResInit() { + private void pm3ResInit(ItemTextBean item) { Activity activity = getActivity(); if (activity != null) { ProDialog1 proDialog1 = new ProDialog1(activity); @@ -173,6 +173,13 @@ public class MainSettingsFragment .copyDirs(new File("pm3"), new File(Paths.TOOLS_DIRECTORY)); proDialog1.dismiss(); showToast(getString(R.string.finished)); + item.setMessage(getString(R.string.initialized)); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + multiTypeAdapter.notifyDataSetChanged(); + } + }); } }).start(); } diff --git a/app_main/src/main/java/cn/rrg/rdv/fragment/tools/ToolsAccessFragment.java b/app_main/src/main/java/cn/rrg/rdv/fragment/tools/ToolsAccessFragment.java index 2b0dfce7..a9ad6234 100644 --- a/app_main/src/main/java/cn/rrg/rdv/fragment/tools/ToolsAccessFragment.java +++ b/app_main/src/main/java/cn/rrg/rdv/fragment/tools/ToolsAccessFragment.java @@ -12,12 +12,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import com.proxgrind.pm3flasher.Proxmark3Flasher; + import cn.rrg.rdv.R; import cn.rrg.rdv.activities.tools.DumpEqualActivity; import cn.rrg.rdv.activities.tools.DumpListActivity; import cn.rrg.rdv.activities.tools.FileListActivity; import cn.rrg.rdv.activities.tools.FormatCovertActivity; import cn.rrg.rdv.activities.tools.KeyFileListActivity; +import cn.rrg.rdv.activities.tools.Proxmark3FirmwareActivity; import cn.rrg.rdv.fragment.base.BaseFragment; public class ToolsAccessFragment @@ -27,6 +30,7 @@ public class ToolsAccessFragment private Button btnKeyEditor = null; private Button btnFormatCovert = null; private Button btnDiffTools = null; + private Button btnPM3Flasher; @Nullable @Override @@ -47,23 +51,22 @@ public class ToolsAccessFragment btnKeyEditor = view.findViewById(R.id.btnKeyEditor); btnFormatCovert = view.findViewById(R.id.btnConvertFormat); btnDiffTools = view.findViewById(R.id.btnDiffTool); + btnPM3Flasher = view.findViewById(R.id.btnPM3Flasher); } private void initActions(Context context) { - //设置数据编辑的按钮的接口实现 btnDataEditor.setOnClickListener(v -> { startActivity(new Intent(context, DumpListActivity.class).putExtra("mode", DumpListActivity.MODE.EDIT)); }); - //数据对比 btnDiffTools.setOnClickListener(v -> startActivity(new Intent(context, DumpEqualActivity.class))); - //格式转换act btnFormatCovert.setOnClickListener(v -> startActivity(new Intent(context, FormatCovertActivity.class))); - //设置密钥编辑的按钮的接口实现 btnKeyEditor.setOnClickListener(v -> startActivity( new Intent(context, KeyFileListActivity.class).putExtra("mode", FileListActivity.MODE.EDIT)) ); + + btnPM3Flasher.setOnClickListener(v -> startActivity(new Intent(context, Proxmark3FirmwareActivity.class))); } } diff --git a/app_main/src/main/java/cn/rrg/rdv/util/Commons.java b/app_main/src/main/java/cn/rrg/rdv/util/Commons.java index a7c81a03..46163e9f 100644 --- a/app_main/src/main/java/cn/rrg/rdv/util/Commons.java +++ b/app_main/src/main/java/cn/rrg/rdv/util/Commons.java @@ -191,4 +191,11 @@ public class Commons { String[] list = pm3Path.list(); return list != null && list.length > 0; } + + public static File createTmpFile(String fileName) { + File file = new File(application.getCacheDir(), fileName); + FileUtils.delete(file); + FileUtils.createFile(file); + return file; + } } diff --git a/app_main/src/main/java/cn/rrg/rdv/util/DumpUtils.java b/app_main/src/main/java/cn/rrg/rdv/util/DumpUtils.java index 18eca7ab..53abf489 100644 --- a/app_main/src/main/java/cn/rrg/rdv/util/DumpUtils.java +++ b/app_main/src/main/java/cn/rrg/rdv/util/DumpUtils.java @@ -669,8 +669,7 @@ public class DumpUtils { String[] datas = new String[aBean.getDatas().length]; //取出块数据 String[] tmpA = aBeanDatas; - String[] tmpB = bBean.getDatas() == null ? - getEmptyM1Bean(bBean.getSector()).getDatas() : bBean.getDatas(); + String[] tmpB = bBean.getDatas() == null ? getEmptyM1Bean(bBean.getSector()).getDatas() : bBean.getDatas(); for (int i = 0; i <= last; ++i) { //先判断两组块数据是否相同 if (tmpA[i].equals(tmpB[i])) { @@ -678,29 +677,28 @@ public class DumpUtils { datas[i] = tmpA[i]; } else { if (i != last) { - //否则判断哪个数据是有效的,如果全部为零则优先考虑其他的情况! - //将有效的数据合并到ret中,优先用KeyB的数据! + //否则是否全都是0,如果全部为零则优先考虑其他的情况! boolean isADataAllZero = isBlockAllZero(tmpA[i]); boolean isBDataAllZero = isBlockAllZero(tmpB[i]); // 两者都是零,说明数据真的是0 if (isADataAllZero && isBDataAllZero) { // 开始选择用正确的数据 - if (DumpUtils.isBlockData(tmpB[i])) { + if (DumpUtils.isValidBlockData(tmpB[i])) { datas[i] = tmpB[i]; - } else if (DumpUtils.isBlockData(tmpA[i])) { + } else if (DumpUtils.isValidBlockData(tmpA[i])) { datas[i] = tmpA[i]; } else { - //不符合数据规范,填充异常字符,跳过操作 + //不符合数据规范,跳过操作 datas[i] = DumpUtils.BLANK_DATA; } } else { // 开始选择用正确的数据 - if (DumpUtils.isBlockData(tmpB[i]) && isADataAllZero) { + if (DumpUtils.isValidBlockData(tmpB[i]) && isADataAllZero) { datas[i] = tmpB[i]; - } else if (DumpUtils.isBlockData(tmpA[i]) && isBDataAllZero) { + } else if (DumpUtils.isValidBlockData(tmpA[i]) && isBDataAllZero) { datas[i] = tmpA[i]; } else { - //不符合数据规范,填充异常字符,跳过操作 + //不符合数据规范,跳过操作 datas[i] = DumpUtils.BLANK_DATA; } } @@ -716,10 +714,10 @@ public class DumpUtils { // 随便填充一个就行了! datas[i] = tmpA[i]; } else { - if (DumpUtils.isBlockData(tmpB[i]) && isADataTrialerAllDefault) { + if (DumpUtils.isValidBlockData(tmpB[i]) && isADataTrialerAllDefault) { //有效的尾部块 datas[i] = tmpB[i]; - } else if (DumpUtils.isBlockData(tmpA[i]) && isBDataTrialerAllDefault) { + } else if (DumpUtils.isValidBlockData(tmpA[i]) && isBDataTrialerAllDefault) { datas[i] = tmpA[i]; } else { //有效的尾部块 diff --git a/app_main/src/main/res/layout/act_common_tools.xml b/app_main/src/main/res/layout/act_common_tools.xml index 440e4569..811cebed 100644 --- a/app_main/src/main/res/layout/act_common_tools.xml +++ b/app_main/src/main/res/layout/act_common_tools.xml @@ -49,6 +49,20 @@ android:text="@string/key_editor" android:textAllCaps="false" /> +