added a picture viewer in QT to be used with hf emrtd

This commit is contained in:
iceman1001 2021-07-05 13:42:33 +02:00
commit 20fe52f8eb
11 changed files with 306 additions and 7 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Added a picture viewer in QT. To be used with `hf emrtd info` (@iceman1001)
- Fix - move des functions to libcrypto (@merlokk)
- Added `CLIGetOptionList` to cliparser that makes it easier to implement text options in the cli (@merlokk)
- Added experimental support for macOS users utilizing MacPorts instead of Homebrew (@linuxgemini)

View file

@ -229,6 +229,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui
${PM3_ROOT}/client/src/ui/image.ui
${PM3_ROOT}/client/src/aiddesfire.c
${PM3_ROOT}/client/src/aidsearch.c
${PM3_ROOT}/client/src/cmdanalyse.c

View file

@ -657,9 +657,9 @@ OBJS += $(OBJCSRCS:%.m=$(OBJDIR)/%.o)
BINS = proxmark3
CLEAN = $(BINS) src/version_pm3.c src/*.moc.cpp src/ui/ui_overlays.h lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
CLEAN = $(BINS) src/version_pm3.c src/*.moc.cpp src/ui/ui_overlays.h src/ui/ui_image.h lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lua
# transition: cleaning also old path stuff
CLEAN += flasher *.moc.cpp ui/ui_overlays.h
CLEAN += flasher *.moc.cpp ui/ui_overlays.h ui/ui_image.h
###########
# targets #
@ -675,7 +675,7 @@ proxmark3: $(OBJS) $(STATICLIBS) lualibs/pm3_cmd.lua lualibs/mfc_default_keys.lu
$(info [=] LD $@)
$(Q)$(LD) $(PM3LDFLAGS) $(OBJS) $(STATICLIBS) $(LDLIBS) -o $@
src/proxgui.cpp: src/ui/ui_overlays.h
src/proxgui.cpp: src/ui/ui_overlays.h src/ui/ui_image.h
src/proxguiqt.moc.cpp: src/proxguiqt.h
$(info [-] MOC $@)
@ -685,6 +685,10 @@ src/ui/ui_overlays.h: src/ui/overlays.ui
$(info [-] UIC $@)
$(Q)$(UIC) $^ > $@
src/ui/ui_image.h: src/ui/image.ui
$(info [-] UIC $@)
$(Q)$(UIC) $^ > $@
lualibs/pm3_cmd.lua: ../include/pm3_cmd.h
$(info [=] GEN $@)
$(Q)awk -f pm3_cmd_h2lua.awk $^ > $@

View file

@ -24,6 +24,8 @@
#include "crapto1/crapto1.h" // prng_successor
#include "commonutil.h" // num_to_bytes
#include "util_posix.h" // msclock
#include "ui.h" // searchhomedirectory
#include "proxgui.h" // Picture Window
// Max file size in bytes. Used in several places.
// Average EF_DG2 seems to be around 20-25kB or so, but ICAO doesn't set an upper limit
@ -53,6 +55,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length, const c
static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length, const char *path);
static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen);
static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen);
static int emrtd_print_ef_dg2_info(uint8_t *data, size_t datalen);
static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen);
static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen);
static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen);
@ -84,7 +87,7 @@ static emrtd_dg_t dg_table[] = {
// tag dg# fileid filename desc pace eac req fast parser dumper
{0x60, 0, 0x011E, "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL},
{0x61, 1, 0x0101, "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL},
{0x75, 2, 0x0102, "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2},
{0x75, 2, 0x0102, "EF_DG2", "Encoded Face", false, false, true, false, emrtd_print_ef_dg2_info, emrtd_dump_ef_dg2},
{0x63, 3, 0x0103, "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL},
{0x76, 4, 0x0104, "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL},
{0x65, 5, 0x0105, "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5},
@ -1398,6 +1401,65 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) {
return PM3_SUCCESS;
}
static int emrtd_print_ef_dg2_info(uint8_t *data, size_t datalen) {
int offset = 0;
// This is a hacky impl that just looks for the image header. I'll improve it eventually.
// based on mrpkey.py
// Note: Doing datalen - 6 to account for the longest data we're checking.
// Checks first byte before the rest to reduce overhead
for (offset = 0; offset < datalen - 6; offset++) {
if ((data[offset] == 0xFF && memcmp(jpeg_header, data + offset, 4) == 0) ||
(data[offset] == 0x00 && memcmp(jpeg2k_header, data + offset, 6) == 0)) {
datalen = datalen - offset;
break;
}
}
// If we didn't get any data, return false.
if (datalen == 0) {
return PM3_ESOFT;
}
bool is_jpg = (data[offset] == 0xFF);
char *fn = calloc( strlen(dg_table[EF_DG2].filename) + 4 + 1, sizeof(uint8_t));
if (fn == NULL)
return PM3_EMALLOC;
sprintf(fn, "%s.%s", dg_table[EF_DG2].filename, (is_jpg) ? "jpg" : "jp2");
PrintAndLogEx(DEBUG, "image filename `" _YELLOW_("%s") "`", fn);
char *path;
if (searchHomeFilePath(&path, NULL, fn, false) != PM3_SUCCESS) {
free(fn);
return PM3_EFILE;
}
free(fn);
// remove old file
if (fileExists(path)) {
PrintAndLogEx(DEBUG, "Delete old temp file `" _YELLOW_("%s") "`", path);
remove(path);
}
// temp file.
PrintAndLogEx(DEBUG, "Save temp file `" _YELLOW_("%s") "`", path);
saveFile(path, "", data + offset, datalen);
PrintAndLogEx(DEBUG, "view temp file `" _YELLOW_("%s") "`", path);
ShowPictureWindow(path);
msleep(500);
// delete temp file
PrintAndLogEx(DEBUG, "Deleting temp file `" _YELLOW_("%s") "`", path);
remove(path);
//free(path);
return PM3_SUCCESS;
}
static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) {
uint8_t taglist[100] = { 0x00 };
size_t taglistlen = 0;
@ -1930,6 +1992,7 @@ int infoHF_EMRTD_offline(const char *path) {
if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) {
emrtd_print_ef_cardaccess_info(data, datalen);
free(data);
} else {
PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE.");
}
@ -2184,12 +2247,12 @@ static int CmdHFeMRTDInfo(const char *Cmd) {
}
}
uint8_t path[FILENAME_MAX] = { 0x00 };
bool offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0;
bool is_offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0;
CLIParserFree(ctx);
if (error) {
return PM3_ESOFT;
}
if (offline) {
if (is_offline) {
return infoHF_EMRTD_offline((const char *)path);
} else {
bool restore_apdu_logging = GetAPDULogging();

View file

@ -13,6 +13,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct emrtd_dg_s {
uint8_t tag;
uint8_t dgnum;
@ -53,4 +57,8 @@ int CmdHFeMRTD(const char *Cmd);
int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path);
int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available);
int infoHF_EMRTD_offline(const char *path);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -21,6 +21,18 @@ extern "C" void ShowGraphWindow(void) {
extern "C" void HideGraphWindow(void) {}
extern "C" void RepaintGraphWindow(void) {}
extern "C" void ShowPictureWindow(char *fn) {
static int warned = 0;
if (!warned) {
printf("No GUI in this build!\n");
warned = 1;
}
}
extern "C" void HidePictureWindow(void) {}
extern "C" void RepaintPictureWindow(void) {}
extern "C" void MainGraphics() {}
extern "C" void InitGraphics(int argc, char **argv) {}
extern "C" void ExitGraphics(void) {}

View file

@ -40,6 +40,7 @@ extern "C" void ShowGraphWindow(void) {
}
gui->ShowGraphWindow();
}
extern "C" void HideGraphWindow(void) {
@ -56,6 +57,36 @@ extern "C" void RepaintGraphWindow(void) {
gui->RepaintGraphWindow();
}
// hook up picture viewer
extern "C" void ShowPictureWindow(char *fn) {
if (!gui) {
// Show a notice if X11/XQuartz isn't available
#if defined(__MACH__) && defined(__APPLE__)
PrintAndLogEx(WARNING, "You appear to be on a MacOS device without XQuartz.\nYou may need to install XQuartz (https://www.xquartz.org/) to make the plot work.");
#else
PrintAndLogEx(WARNING, "You appear to be on an environment without an X11 server or without DISPLAY environment variable set.\nPlot may not work until you resolve these issues.");
#endif
return;
}
gui->ShowPictureWindow(fn);
}
extern "C" void HidePictureWindow(void) {
if (!gui)
return;
gui->HidePictureWindow();
}
extern "C" void RepaintPictureWindow(void) {
if (!gui)
return;
gui->RepaintPictureWindow();
}
extern "C" void MainGraphics(void) {
if (!gui)
return;

View file

@ -22,6 +22,12 @@ extern "C" {
void ShowGraphWindow(void);
void HideGraphWindow(void);
void RepaintGraphWindow(void);
// hook up picture viewer
void ShowPictureWindow(char *fn);
void HidePictureWindow(void);
void RepaintPictureWindow(void);
void MainGraphics(void);
void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cmd, bool stayInCommandLoop);
void ExitGraphics(void);

View file

@ -12,6 +12,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <iostream>
//#include <QtCore>
#include <QPainterPath>
#include <QBrush>
#include <QPen>
@ -32,6 +33,7 @@
#include "graph.h"
#include "cmddata.h"
#include "util_darwin.h"
//#include "fileutils.h"
extern "C" int preferences_save(void);
@ -54,6 +56,19 @@ void ProxGuiQT::HideGraphWindow(void) {
emit HideGraphWindowSignal();
}
// emit picture viewer signals
void ProxGuiQT::ShowPictureWindow(char *fn) {
emit ShowPictureWindowSignal(fn);
}
void ProxGuiQT::RepaintPictureWindow(void) {
emit RepaintPictureWindowSignal();
}
void ProxGuiQT::HidePictureWindow(void) {
emit HidePictureWindowSignal();
}
void ProxGuiQT::Exit(void) {
emit ExitSignal();
}
@ -71,6 +86,7 @@ void ProxGuiQT::_ShowGraphWindow(void) {
plotwidget = new ProxWidget();
}
plotwidget->show();
}
void ProxGuiQT::_RepaintGraphWindow(void) {
@ -87,10 +103,80 @@ void ProxGuiQT::_HideGraphWindow(void) {
plotwidget->hide();
}
// picture viewer
void ProxGuiQT::_ShowPictureWindow(char *fn) {
if (fn == NULL)
return;
size_t slen = strlen(fn);
if (slen == 0)
return;
char *myfn = (char*)calloc(slen + 1, sizeof(uint8_t));
if (myfn == NULL)
return;
memcpy(myfn, fn, slen);
if (!plotapp)
return;
if (!pictureWidget) {
#if defined(__MACH__) && defined(__APPLE__)
makeFocusable();
#endif
pictureWidget = new QWidget();
}
QPixmap pm;
if(pm.load(myfn) == false){
qWarning("Failed to load %s", myfn);
}
free(myfn);
free(fn);
//QPixmap newPixmap = pm.scaled(QSize(50,50), Qt::KeepAspectRatio);
//pm = pm.scaled(pictureController->lbl_pm->size(), Qt::KeepAspectRatio);
pictureController->lbl_pm->setPixmap(pm);
pictureController->lbl_pm->setScaledContents(false);
pictureController->lbl_pm->setAlignment(Qt::AlignCenter);
QString s = QString("w: %1 h: %2")
.arg(pm.size().width())
.arg(pm.size().height()
);
pictureController->lbl_sz->setText(s);
pictureWidget->show();
}
void ProxGuiQT::_RepaintPictureWindow(void) {
if (!plotapp || !pictureWidget)
return;
pictureWidget->update();
}
void ProxGuiQT::_HidePictureWindow(void) {
if (!plotapp || !pictureWidget)
return;
pictureWidget->hide();
}
void ProxGuiQT::_Exit(void) {
delete this;
}
void ProxGuiQT::closeEvent(QCloseEvent *event) {
event->ignore();
pictureWidget->hide();
}
void ProxGuiQT::hideEvent(QHideEvent *event) {
pictureWidget->hide();
}
void ProxGuiQT::_StartProxmarkThread(void) {
if (!proxmarkThread)
return;
@ -105,11 +191,23 @@ void ProxGuiQT::_StartProxmarkThread(void) {
void ProxGuiQT::MainLoop() {
plotapp = new QApplication(argc, argv);
// Setup the picture widget
pictureWidget = new QWidget();
pictureController = new Ui::PictureForm();
pictureController->setupUi(pictureWidget);
connect(this, SIGNAL(ShowGraphWindowSignal()), this, SLOT(_ShowGraphWindow()));
connect(this, SIGNAL(RepaintGraphWindowSignal()), this, SLOT(_RepaintGraphWindow()));
connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow()));
connect(this, SIGNAL(ExitSignal()), this, SLOT(_Exit()));
// hook up picture viewer signals
connect(this, SIGNAL(ShowPictureWindowSignal(char*)), this, SLOT(_ShowPictureWindow(char*)));
connect(this, SIGNAL(RepaintPictureWindowSignal()), this, SLOT(_RepaintPictureWindow()));
connect(this, SIGNAL(HidePictureWindowSignal()), this, SLOT(_HidePictureWindow()));
//start proxmark thread after starting event loop
QTimer::singleShot(200, this, SLOT(_StartProxmarkThread()));
@ -127,6 +225,18 @@ ProxGuiQT::ProxGuiQT(int argc, char **argv, WorkerThread *wthread) : plotapp(NUL
}
ProxGuiQT::~ProxGuiQT(void) {
if (pictureController) {
delete pictureController;
pictureController = NULL;
}
if (pictureWidget) {
pictureWidget->close();
delete pictureWidget;
pictureWidget = NULL;
}
if (plotapp) {
plotapp->quit();
plotapp = NULL;
@ -197,6 +307,8 @@ void ProxWidget::vchange_dthr_down(int v) {
g_useOverlays = true;
RepaintGraphWindow();
}
ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
this->master = master;
// Set the initail postion and size from settings
@ -207,6 +319,7 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
// Setup the controller widget
controlWidget = new SliderWidget(); //new QWidget();
opsController = new Ui::Form();
opsController->setupUi(controlWidget);
//Due to quirks in QT Designer, we need to fiddle a bit
@ -295,6 +408,7 @@ void ProxWidget::showEvent(QShowEvent *event) {
controlWidget->show();
else
controlWidget->hide();
plot->show();
}
void ProxWidget::moveEvent(QMoveEvent *event) {

View file

@ -22,6 +22,7 @@
#include <QtGui>
#include "ui/ui_overlays.h"
#include "ui/ui_image.h"
class ProxWidget;
@ -81,8 +82,8 @@ class ProxWidget : public QWidget {
ProxGuiQT *master;
Plot *plot;
Ui::Form *opsController;
// QWidget *controlWidget;
SliderWidget *controlWidget;
public:
ProxWidget(QWidget *parent = 0, ProxGuiQT *master = NULL);
~ProxWidget(void);
@ -125,6 +126,10 @@ class ProxGuiQT : public QObject {
private:
QApplication *plotapp;
ProxWidget *plotwidget;
Ui::PictureForm *pictureController;
QWidget *pictureWidget;
int argc;
char **argv;
//void (*main_func)(void);
@ -136,13 +141,29 @@ class ProxGuiQT : public QObject {
void ShowGraphWindow(void);
void RepaintGraphWindow(void);
void HideGraphWindow(void);
// hook up picture viewer
void ShowPictureWindow(char *fn);
void HidePictureWindow(void);
void RepaintPictureWindow(void);
void MainLoop(void);
void Exit(void);
protected:
void closeEvent(QCloseEvent *event);
void hideEvent(QHideEvent *event);
private slots:
void _ShowGraphWindow(void);
void _RepaintGraphWindow(void);
void _HideGraphWindow(void);
// hook up picture viewer
void _ShowPictureWindow(char *fn);
void _HidePictureWindow(void);
void _RepaintPictureWindow(void);
void _Exit(void);
void _StartProxmarkThread(void);
@ -151,6 +172,11 @@ class ProxGuiQT : public QObject {
void RepaintGraphWindowSignal(void);
void HideGraphWindowSignal(void);
void ExitSignal(void);
// hook up picture viewer signals
void ShowPictureWindowSignal(char *fn);
void HidePictureWindowSignal(void);
void RepaintPictureWindowSignal(void);
};
#endif // PROXGUI_QT

33
client/src/ui/image.ui Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PictureForm</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Picture Viewer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<widget class="QLabel" name="lbl_pm">
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_sz">
<property name="text">
<string>Image size</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>