mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-23 13:03:13 +00:00
Merge pull request #3404 from dangerous-tac0s/hf-mfu-esetblk
Hf mfu esetblk
This commit is contained in:
2 files changed
+94
-14
No files matched your search
+27
-14
@@ -1644,18 +1644,21 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
|
||||
AddCrc14A(rPPS, sizeof(rPPS) - 2);
|
||||
|
||||
// EV1/NTAG, set PWD w AMIIBO algo if all zero.
|
||||
// EV1/NTAG Amiibo: if no PWD is set, populate emulator memory with the UID-derived
|
||||
// password and its PACK (0x8080) at the PWD/PACK pages, so the sim serves them from
|
||||
// emulator memory like any other value. Auth and PACK are then read straight from
|
||||
// memory, keeping eset/eview authoritative (what you set is what the sim serves).
|
||||
if (tagType == 7) {
|
||||
uint8_t pwd[4] = {0, 0, 0, 0};
|
||||
uint8_t gen_pwd[4] = {0, 0, 0, 0};
|
||||
emlGet(pwd, (*pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd));
|
||||
emlGet(rPACK, (*pages) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(rPACK));
|
||||
|
||||
Uint4byteToMemBe(gen_pwd, ul_ev1_pwdgenB(data));
|
||||
if (memcmp(pwd, gen_pwd, sizeof(pwd)) == 0) {
|
||||
rPACK[0] = 0x80;
|
||||
rPACK[1] = 0x80;
|
||||
if (memcmp(pwd, "\x00\x00\x00\x00", 4) == 0) {
|
||||
uint8_t amiibo_pwd[4] = {0, 0, 0, 0};
|
||||
Uint4byteToMemLe(amiibo_pwd, ul_ev1_pwdgenB(data));
|
||||
emlSet(amiibo_pwd, (*pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(amiibo_pwd));
|
||||
uint8_t amiibo_pack[4] = {0x80, 0x80, 0x00, 0x00};
|
||||
emlSet(amiibo_pack, (*pages) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(amiibo_pack));
|
||||
}
|
||||
emlGet(rPACK, (*pages) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(rPACK));
|
||||
}
|
||||
|
||||
AddCrc14A(rPACK, sizeof(rPACK) - 2);
|
||||
@@ -2347,14 +2350,24 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
|
||||
Dbhexdump(4, pwd, 0);
|
||||
}
|
||||
|
||||
if (memcmp(pwd, "\x00\x00\x00\x00", 4) == 0) {
|
||||
Uint4byteToMemLe(pwd, ul_ev1_pwdgenB(useruid));
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Calc pwd... %02X %02X %02X %02X", pwd[0], pwd[1], pwd[2], pwd[3]);
|
||||
}
|
||||
|
||||
// PWD comes straight from emulator memory (read above). For an unset (all-zero)
|
||||
// PWD, the Amiibo password is populated into memory at sim init, so there's no
|
||||
// substitution here -- eset/eview stay authoritative.
|
||||
if (memcmp(receivedCmd + 1, pwd, 4) == 0) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Password match, responding with PACK.");
|
||||
p_response = &responses[RESP_INDEX_PACK];
|
||||
|
||||
// Serve PACK straight from the PACK page (page `pages`) in emulator memory, so
|
||||
// eset/eload of the PACK page is honored live. The Amiibo PACK (0x8080) for an
|
||||
// unset PWD is populated into memory at sim init, so nothing special-cases here.
|
||||
uint8_t pack_live[4] = {0, 0, 0, 0};
|
||||
emlGet(pack_live, pages * 4 + MFU_DUMP_PREFIX_LENGTH, 2);
|
||||
|
||||
dynamic_response_info.response[0] = pack_live[0];
|
||||
dynamic_response_info.response[1] = pack_live[1];
|
||||
AddCrc14A(dynamic_response_info.response, 2);
|
||||
dynamic_response_info.response_n = 4; // 2 PACK + 2 CRC
|
||||
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
|
||||
p_response = &dynamic_response_info;
|
||||
} else {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Password did not match, NACK_IV.");
|
||||
p_response = NULL;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "aes.h"
|
||||
#include "cmdhfmf.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "mifare/mifarehost.h" // mf_eml_set_mem_xt
|
||||
#include "comms.h"
|
||||
#include "protocols.h"
|
||||
#include "generator.h"
|
||||
@@ -8053,6 +8054,71 @@ static int CmdHF14AMfUIncr(const char *Cmd) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AMfUeSetBlk(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfu esetblk",
|
||||
"Set emulator memory page(s). One page = 4 bytes; pass multiple\n"
|
||||
"whole pages of data to set consecutive pages from --blk.",
|
||||
"hf mfu esetblk --blk 4 -d 04E10CDA\n"
|
||||
"hf mfu esetblk --blk 4 -d 04E10CDA993C8048 -> sets pages 4-5\n"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("b", "blk", "<dec>", "page number to start at"),
|
||||
arg_str0("d", "data", "<hex>", "bytes to write, whole pages (multiple of 4 bytes)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int blk = arg_get_int_def(ctx, 1, 0);
|
||||
|
||||
uint8_t data[MFU_MAX_BYTES] = {0x00};
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), data, sizeof(data), &datalen);
|
||||
CLIParserFree(ctx);
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "Error parsing bytes");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (blk < 0) {
|
||||
PrintAndLogEx(WARNING, "page number must be positive");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (datalen == 0 || (datalen % MFU_BLOCK_SIZE) != 0) {
|
||||
PrintAndLogEx(WARNING, "data must be whole pages (multiples of %d bytes). Got %i", MFU_BLOCK_SIZE, datalen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int count = datalen / MFU_BLOCK_SIZE;
|
||||
|
||||
// live MFU emulator data region is MFU_MAX_BYTES (pages 0..254); page 255 is not round-trippable
|
||||
if ((blk + count) * MFU_BLOCK_SIZE > MFU_MAX_BYTES) {
|
||||
PrintAndLogEx(WARNING, "page range exceeds emulator memory (max page %u)", (MFU_MAX_BYTES / MFU_BLOCK_SIZE) - 1);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// one esetblk is a single CMD_HF_MIFARE_EML_MEMSET; its payload (data + a 4-byte
|
||||
// header) must fit the command buffer. Larger sets should use `hf mfu eload`.
|
||||
if (datalen > (int)(PM3_CMD_DATA_SIZE - 4)) {
|
||||
PrintAndLogEx(WARNING, "too many pages for one command: max %d pages (%d bytes). Use " _YELLOW_("`hf mfu eload`") " for larger sets",
|
||||
(int)((PM3_CMD_DATA_SIZE - 4) / MFU_BLOCK_SIZE), (int)(PM3_CMD_DATA_SIZE - 4));
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// MFU emulator page data starts after the 56-byte mfu_dump_t prefix, so shift the
|
||||
// page index by MFU_DUMP_PREFIX_LENGTH/MFU_BLOCK_SIZE (=14), width = MFU_BLOCK_SIZE (4).
|
||||
res = mf_eml_set_mem_xt(data, blk + (MFU_DUMP_PREFIX_LENGTH / MFU_BLOCK_SIZE), count, MFU_BLOCK_SIZE);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Failed to set emulator memory");
|
||||
return res;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Set " _YELLOW_("%d") " page(s) from page " _YELLOW_("%d"), count, blk);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AMfuList, AlwaysAvailable, "List MIFARE Ultralight / NTAG history"},
|
||||
@@ -8082,6 +8148,7 @@ static command_t CommandTable[] = {
|
||||
{"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Upload file into emulator memory"},
|
||||
{"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save emulator memory to file"},
|
||||
{"eview", CmdHF14AMfuEView, IfPm3Iso14443a, "View emulator memory"},
|
||||
{"esetblk", CmdHF14AMfUeSetBlk, IfPm3Iso14443a, "Set emulator memory block"},
|
||||
{"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate MIFARE Ultralight from emulator memory"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " ----------------------------"},
|
||||
{"setuid", CmdHF14AMfUCSetUid, IfPm3Iso14443a, "Set UID - MAGIC tags only"},
|
||||
|
||||
Reference in new issue
Block a user