From fe40e23c857b1f0d45011383570da58a63c9d556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=90=E6=AD=AA?= Date: Thu, 20 Aug 2026 06:09:10 +0800 Subject: [PATCH 1/5] feat: auto gdm_wakeup_attempts --- client/src/cmdhfmf.c | 190 ++++++++++++++++++++++++++++++------------- 1 file changed, 134 insertions(+), 56 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 2ebc9a608..5ee4ad8c3 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -9735,6 +9735,94 @@ static int gdm_resolve_wakeup(bool gdm, bool gen1a, bool wupa, int keylen, return PM3_SUCCESS; } +// A single wakeup/auth attempt: wakeup type, magic-auth command, and key. +typedef struct { + uint8_t wakeup_type; + uint8_t auth_cmd; + uint8_t key[6]; +} gdm_wakeup_t; + +static const char *gdm_wakeup_name(const gdm_wakeup_t *w) { + if (w->auth_cmd == MIFARE_MAGIC_GDM_AUTH_KEY) { + return "WUPA + magic auth"; + } + if (w->wakeup_type == MF_WAKE_GEN1A) { + return "gen1a (40/43)"; + } + return "gdm alt (20/23)"; +} + +// Build the list of wakeup attempts a read command should try. With an explicit +// mode (--gdm/--gen1a/--wupa, or a key) there is exactly one attempt. With nothing +// specified, returns all three access paths (gen1a, gdm alt, WUPA + magic auth with +// an all-zero key) so a card that only enables one of them is still reachable. +// `prefer_auth` puts WUPA magic auth first - use it for config reads (magic auth can +// read the config block); leave it false for data-block reads, where the backdoor +// wakeups are tried first (magic auth usually cannot read normal/hidden blocks). +static int gdm_wakeup_attempts(bool gdm, bool gen1a, bool wupa, const uint8_t *key, int keylen, + bool prefer_auth, gdm_wakeup_t attempts[3], int *count) { + if (gdm || gen1a || wupa || keylen > 0) { + uint8_t wt = 0, ac = 0; + if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wt, &ac) != PM3_SUCCESS) { + return PM3_EINVARG; + } + attempts[0].wakeup_type = wt; + attempts[0].auth_cmd = ac; + memcpy(attempts[0].key, key, 6); + *count = 1; + return PM3_SUCCESS; + } + + static const uint8_t types_blk[3] = { MF_WAKE_GEN1A, MF_WAKE_GDM_ALT, MF_WAKE_WUPA }; + static const uint8_t auths_blk[3] = { 0, 0, MIFARE_MAGIC_GDM_AUTH_KEY }; + static const uint8_t types_auth[3] = { MF_WAKE_WUPA, MF_WAKE_GEN1A, MF_WAKE_GDM_ALT }; + static const uint8_t auths_auth[3] = { MIFARE_MAGIC_GDM_AUTH_KEY, 0, 0 }; + const uint8_t *types = prefer_auth ? types_auth : types_blk; + const uint8_t *auths = prefer_auth ? auths_auth : auths_blk; + for (int i = 0; i < 3; i++) { + attempts[i].wakeup_type = types[i]; + attempts[i].auth_cmd = auths[i]; + memset(attempts[i].key, 0, 6); + } + *count = 3; + return PM3_SUCCESS; +} + +// Read a single block with one wakeup attempt. Quiet: returns status, prints nothing. +static int gdm_try_read(uint8_t read_cmd, int block_no, const gdm_wakeup_t *w, uint8_t *out) { + mf_readblock_ex_t payload = { + .read_cmd = read_cmd, + .block_no = block_no, + .wakeup = w->wakeup_type, + .auth_cmd = w->auth_cmd + }; + memcpy(payload.key, w->key, sizeof(payload.key)); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL_EX, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX, &resp, 1500) == false) { + return PM3_ETIMEOUT; + } + if (resp.status != PM3_SUCCESS || resp.length != MFBLOCK_SIZE) { + return PM3_EFAILED; + } + memcpy(out, resp.data.asBytes, MFBLOCK_SIZE); + return PM3_SUCCESS; +} + +// Try each attempt against `probe_blk`; return the index of the first that reads +// successfully (data in `out`), or -1 if all fail. +static int gdm_pick_wakeup(uint8_t read_cmd, int probe_blk, const gdm_wakeup_t *attempts, + int count, uint8_t *out) { + for (int i = 0; i < count; i++) { + if (gdm_try_read(read_cmd, probe_blk, &attempts[i], out) == PM3_SUCCESS) { + return i; + } + } + return -1; +} + // Read an string option into a tri-state: 1 = on, 0 = off, -1 = not provided. static int gdm_arg_onoff(CLIParserContext *ctx, int idx) { struct arg_str *a = arg_get_str(ctx, idx); @@ -9752,7 +9840,8 @@ static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmgetcfg", "Get configuration data from a GDM card.\n" - "By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override.", + "With no wakeup flag it auto-detects the card's access mode (tries WUPA magic auth,\n" + "then gen1a, then gdm alt). Use `--gdm`/`--gen1a`/`--wupa` to force one.", "hf mf gdmgetcfg\n" "hf mf gdmgetcfg --gen1a\n" "hf mf gdmgetcfg --wupa -k FFFFFFFFFFFF" @@ -9760,7 +9849,7 @@ static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), arg_param_end @@ -9775,35 +9864,28 @@ static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) { bool wupa = arg_get_lit(ctx, 4); CLIParserFree(ctx); - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { + gdm_wakeup_t attempts[3]; + int n_attempts = 0; + if (gdm_wakeup_attempts(gdm, gen1a, wupa, key, keylen, true, attempts, &n_attempts) != PM3_SUCCESS) { return PM3_EINVARG; } - mf_readblock_ex_t payload = { - .read_cmd = MIFARE_MAGIC_GDM_READ_CFG, - .block_no = 0, - .wakeup = wakeup_type, - .auth_cmd = auth_cmd - }; - memcpy(payload.key, key, sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL_EX, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX, &resp, 1500) == false) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; + uint8_t cfg[MFBLOCK_SIZE] = {0}; + int idx = gdm_pick_wakeup(MIFARE_MAGIC_GDM_READ_CFG, 0, attempts, n_attempts, cfg); + if (idx < 0) { + PrintAndLogEx(FAILED, "Failed to read config block"); + if (n_attempts > 1) { + PrintAndLogEx(HINT, "Hint: tried WUPA/gen1a/gdm wakeups; card may be sealed or use a non-default magic auth key"); + } + return PM3_EFAILED; + } + if (n_attempts > 1) { + PrintAndLogEx(INFO, "Auto-detected wakeup: " _YELLOW_("%s"), gdm_wakeup_name(&attempts[idx])); } - if (resp.status == PM3_SUCCESS && resp.length == MFBLOCK_SIZE) { - parse_gdm_cfg(resp.data.asBytes); - - PrintAndLogEx(NORMAL, ""); - } - - return resp.status; + parse_gdm_cfg(cfg); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; } static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { @@ -10229,40 +10311,34 @@ static int gdm_read_blocks(int blk, int sec, const uint8_t *key, int keylen, return PM3_EINVARG; } - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { + gdm_wakeup_t attempts[3]; + int n_attempts = 0; + if (gdm_wakeup_attempts(gdm, gen1a, wupa, key, keylen, false, attempts, &n_attempts) != PM3_SUCCESS) { return PM3_EINVARG; } int start_blk = (blk != -1) ? blk : mfFirstBlockOfSector(sec); int num_blks = (blk != -1) ? 1 : mfNumBlocksPerSector(sec); - for (int i = 0; i < num_blks; i++) { + // probe the first block to pick a working wakeup, then reuse it for the rest + uint8_t data[MFBLOCK_SIZE] = {0}; + int idx = gdm_pick_wakeup(read_cmd, start_blk, attempts, n_attempts, data); + if (idx < 0) { + PrintAndLogEx(FAILED, "Failed to read %s %d", label, start_blk); + return PM3_EFAILED; + } + if (n_attempts > 1) { + PrintAndLogEx(INFO, "Auto-detected wakeup: " _YELLOW_("%s"), gdm_wakeup_name(&attempts[idx])); + } + PrintAndLogEx(SUCCESS, "%s %3d: %s", label, start_blk, sprint_hex_inrow(data, MFBLOCK_SIZE)); + + for (int i = 1; i < num_blks; i++) { int current_blk = start_blk + i; - - mf_readblock_ex_t payload = { - .read_cmd = read_cmd, - .block_no = current_blk, - .wakeup = wakeup_type, - .auth_cmd = auth_cmd - }; - memcpy(payload.key, key, sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL_EX, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX, &resp, 1500) == false) { - PrintAndLogEx(FAILED, "command execution time out (block %d)", current_blk); - return PM3_ETIMEOUT; - } - - if (resp.status == PM3_SUCCESS && resp.length == MFBLOCK_SIZE) { - PrintAndLogEx(SUCCESS, "%s %3d: %s", label, current_blk, sprint_hex_inrow(resp.data.asBytes, MFBLOCK_SIZE)); - } else { - PrintAndLogEx(FAILED, "Failed to read %s %d. Status: %d", label, current_blk, resp.status); - return resp.status; + if (gdm_try_read(read_cmd, current_blk, &attempts[idx], data) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Failed to read %s %d", label, current_blk); + return PM3_EFAILED; } + PrintAndLogEx(SUCCESS, "%s %3d: %s", label, current_blk, sprint_hex_inrow(data, MFBLOCK_SIZE)); } return PM3_SUCCESS; @@ -10271,7 +10347,8 @@ static int gdm_read_blocks(int blk, int sec, const uint8_t *key, int keylen, static int CmdHF14AGen4_GDM_GetHidBlk(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmgethidblk", - "Read hidden block(s) from a GDM card", + "Read hidden block(s) from a GDM card.\n" + "With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", "hf mf gdmgethidblk --blk 0\n" "hf mf gdmgethidblk --sec 1 --gdm" ); @@ -10280,7 +10357,7 @@ static int CmdHF14AGen4_GDM_GetHidBlk(const char *Cmd) { arg_int0(NULL, "blk", "", "block to read"), arg_int0(NULL, "sec", "", "sector to read"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), arg_param_end @@ -10303,7 +10380,8 @@ static int CmdHF14AGen4_GDM_GetHidBlk(const char *Cmd) { static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmgetblk", - "Read public block(s) from a GDM card", + "Read public block(s) from a GDM card.\n" + "With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", "hf mf gdmgetblk --blk 0\n" "hf mf gdmgetblk --sec 1 --gdm" ); @@ -10312,7 +10390,7 @@ static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { arg_int0(NULL, "blk", "", "block to read"), arg_int0(NULL, "sec", "", "sector to read"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), arg_param_end From 543161bcc230b69a73a6c77bcdc0a0ae707d481d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=90=E6=AD=AA?= Date: Sat, 22 Aug 2026 22:39:58 +0800 Subject: [PATCH 2/5] fix: auto-detect wakeup on all gdm commands and fix gdmwipe --- client/src/cmdhfmf.c | 374 ++++++++++++++++++++++++-------- client/src/pm3line_vocabulary.h | 17 +- doc/commands.json | 235 ++++++++++++++------ doc/commands.md | 9 +- 4 files changed, 459 insertions(+), 176 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 5ee4ad8c3..672ffc4ec 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -9823,6 +9823,78 @@ static int gdm_pick_wakeup(uint8_t read_cmd, int probe_blk, const gdm_wakeup_t * return -1; } +// Resolve which wakeup a WRITE command should use, by probing with a matching READ. +// probe_read_cmd/probe_blk : the read used to test reachability - config (0xE0), +// public block (0x30), or hidden block (0x38). Use the +// read that matches what the command actually writes, so +// a wakeup that cannot reach the write target is rejected +// during the (read-only) probe instead of half-writing. +// needs_backdoor : true for hidden/mixed writes a WUPA-only card cannot do. +// On probe failure it prints a "enable a backdoor" hint and +// returns an error WITHOUT touching the card. +// out_probe_data/out_have_probe (nullable) : receive the block read during a successful +// auto-probe, letting the caller reuse it (e.g. setcfg reusing +// the config it just read). *out_have_probe is false when the +// wakeup was given explicitly (no probe was performed). +// With an explicit wakeup (--gdm/--gen1a/--wupa or a key) there is no probe and behaviour +// is unchanged: exactly the chosen wakeup is returned. +static int gdm_resolve_for_write(bool gdm, bool gen1a, bool wupa, + const uint8_t *key, int keylen, + uint8_t probe_read_cmd, int probe_blk, + bool needs_backdoor, const char *cmd_name, + gdm_wakeup_t *out_w, + uint8_t *out_probe_data, bool *out_have_probe) { + if (out_have_probe != NULL) { + *out_have_probe = false; + } + + bool explicit_mode = (gdm || gen1a || wupa || keylen > 0); + // config reads can use magic auth, so try WUPA first there; for data/hidden reads try + // the backdoors first (magic auth usually cannot reach normal/hidden blocks). + bool prefer_auth = (probe_read_cmd == MIFARE_MAGIC_GDM_READ_CFG); + + gdm_wakeup_t attempts[3]; + int n_attempts = 0; + if (gdm_wakeup_attempts(gdm, gen1a, wupa, key, keylen, prefer_auth, attempts, &n_attempts) != PM3_SUCCESS) { + return PM3_EINVARG; + } + + // Explicit wakeup: do not probe, keep legacy behaviour (single attempt, may fail at write). + if (explicit_mode) { + *out_w = attempts[0]; + return PM3_SUCCESS; + } + + uint8_t buf[MFBLOCK_SIZE] = {0}; + int idx = gdm_pick_wakeup(probe_read_cmd, probe_blk, attempts, n_attempts, buf); + if (idx < 0) { + if (needs_backdoor) { + // Distinguish a WUPA-only (sealed) card from an unreachable one: can WUPA magic + // auth still read the config block? If so, the card is fine but lacks a backdoor. + gdm_wakeup_t w = { .wakeup_type = MF_WAKE_WUPA, .auth_cmd = MIFARE_MAGIC_GDM_AUTH_KEY }; + memset(w.key, 0, sizeof(w.key)); + if (gdm_try_read(MIFARE_MAGIC_GDM_READ_CFG, 0, &w, buf) == PM3_SUCCESS) { + PrintAndLogEx(WARNING, "This card only responds to WUPA magic auth; " _YELLOW_("%s") " needs a gen1a/gdm backdoor", cmd_name); + PrintAndLogEx(HINT, "Hint: enable one first: " _YELLOW_("hf mf gdmsetcfg --wakestyle gen1a --wupa -k ")); + return PM3_EFAILED; + } + } + PrintAndLogEx(FAILED, "Could not find a working wakeup for " _YELLOW_("%s"), cmd_name); + PrintAndLogEx(HINT, "Hint: tried gen1a/gdm/wupa; card may be sealed or use a non-default magic auth key"); + return PM3_EFAILED; + } + + *out_w = attempts[idx]; + if (out_probe_data != NULL) { + memcpy(out_probe_data, buf, MFBLOCK_SIZE); + } + if (out_have_probe != NULL) { + *out_have_probe = true; + } + PrintAndLogEx(INFO, "Auto-detected wakeup: " _YELLOW_("%s"), gdm_wakeup_name(out_w)); + return PM3_SUCCESS; +} + // Read an string option into a tri-state: 1 = on, 0 = off, -1 = not provided. static int gdm_arg_onoff(CLIParserContext *ctx, int idx) { struct arg_str *a = arg_get_str(ctx, idx); @@ -9850,8 +9922,8 @@ static int CmdHF14AGen4_GDM_Cfg(const char *Cmd) { arg_param_begin, arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -9893,25 +9965,31 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { CLIParserInit(&ctx, "hf mf gdmsetcfg", "Set configuration data on a GDM card\n" "Can either write raw 16 bytes (-d) or configure specific flags.\n" - "If flags are provided, it will read the config, update flags, and write it back.", + "If flags are provided, it will read the config, update flags, and write it back.\n" + "With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).\n" + "\n" + "Note the two groups below are different things:\n" + " --gdm / --gen1a / --wupa how THIS command talks to the card (access, not stored)\n" + " --wakestyle / --cuid / ... what gets STORED in the card's config block", "hf mf gdmsetcfg -d 850000000000000000005A5A00000008\n" - "hf mf gdmsetcfg --cuid on --gen1 on\n" + "hf mf gdmsetcfg --cuid on --wakestyle gen1a\n" + "hf mf gdmsetcfg --wakestyle off\n" "hf mf gdmsetcfg --shadow off --sigsec off --wupa -k FFFFFFFFFFFF" ); void *argtable[] = { arg_param_begin, arg_str0("d", "data", "", "raw bytes to write, 16 hex bytes"), arg_str0("k", "key", "", "key 6 bytes (only for regular wakeup)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), - arg_str0(NULL, "gen1", "", "Gen1 mode (7A FF)"), - arg_str0(NULL, "cuid", "", "Gen2/CUID mode"), - arg_str0(NULL, "cl2", "", "CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>` to set a valid UID"), - arg_str0(NULL, "shadow", "", "Shadow mode"), - arg_str0(NULL, "magicauth", "", "Magic auth"), - arg_str0(NULL, "statenc", "", "Static encrypted nonce"), - arg_str0(NULL, "sigsec", "", "Signature sector"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), + arg_str0(NULL, "cuid", "", "config: Gen2/CUID mode"), + arg_str0(NULL, "cl2", "", "config: CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>`"), + arg_str0(NULL, "shadow", "", "config: Shadow mode"), + arg_str0(NULL, "magicauth", "", "config: Magic auth (what --wupa uses)"), + arg_str0(NULL, "statenc", "", "config: Static encrypted nonce"), + arg_str0(NULL, "sigsec", "", "config: Signature sector"), + arg_str0(NULL, "wakestyle", "", "config: backdoor - gdm (7AFF85), gen1a (7AFF00), or off (8500, seal)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -9929,13 +10007,32 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { bool wupa = arg_get_lit(ctx, 5); // read flags into tri-states (1/0/-1) before freeing ctx - int gen1_flag = gdm_arg_onoff(ctx, 6); - int cuid_flag = gdm_arg_onoff(ctx, 7); - int cl2_flag = gdm_arg_onoff(ctx, 8); - int shadow_flag = gdm_arg_onoff(ctx, 9); - int magicauth_flag = gdm_arg_onoff(ctx, 10); - int statenc_flag = gdm_arg_onoff(ctx, 11); - int sigsec_flag = gdm_arg_onoff(ctx, 12); + int cuid_flag = gdm_arg_onoff(ctx, 6); + int cl2_flag = gdm_arg_onoff(ctx, 7); + int shadow_flag = gdm_arg_onoff(ctx, 8); + int magicauth_flag = gdm_arg_onoff(ctx, 9); + int statenc_flag = gdm_arg_onoff(ctx, 10); + int sigsec_flag = gdm_arg_onoff(ctx, 11); + + // Backdoor selector. Sets config byte 0-1 (backdoor on 7AFF / off 8500) and, when + // enabling, byte 2 (style: 85 = GDM 20/23, 00 = gen1a 40/43). This is the only way to + // toggle the backdoor - there is no separate on/off flag. + // gdm -> 7AFF85 gen1a -> 7AFF00 off -> 8500 (byte 2 left as-is) + enum { WS_NONE, WS_GDM, WS_GEN1A, WS_OFF } wakestyle = WS_NONE; + struct arg_str *ws = arg_get_str(ctx, 12); + if (ws->count > 0) { + if (strcasecmp(ws->sval[0], "gdm") == 0) { + wakestyle = WS_GDM; + } else if (strcasecmp(ws->sval[0], "gen1a") == 0) { + wakestyle = WS_GEN1A; + } else if (strcasecmp(ws->sval[0], "off") == 0) { + wakestyle = WS_OFF; + } else { + PrintAndLogEx(FAILED, "--wakestyle must be " _YELLOW_("gdm") ", " _YELLOW_("gen1a") " or " _YELLOW_("off") ", got `%s`", ws->sval[0]); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } CLIParserFree(ctx); @@ -9944,14 +10041,24 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { return PM3_EINVARG; } - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a config read; the config block is reachable via WUPA + // magic auth as well as either backdoor, so no backdoor is required here. + gdm_wakeup_t gw; + uint8_t probe_cfg[MFBLOCK_SIZE] = {0}; + bool have_probe = false; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + MIFARE_MAGIC_GDM_READ_CFG, 0, false, "hf mf gdmsetcfg", + &gw, probe_cfg, &have_probe); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); - bool any_flag = (gen1_flag != -1 || cuid_flag != -1 || cl2_flag != -1 || shadow_flag != -1 || - magicauth_flag != -1 || statenc_flag != -1 || sigsec_flag != -1); + bool any_flag = (cuid_flag != -1 || cl2_flag != -1 || shadow_flag != -1 || + magicauth_flag != -1 || statenc_flag != -1 || sigsec_flag != -1 || + wakestyle != WS_NONE); // Logic: if -d is specified, write raw block. // Else, read config, update flags, write block. @@ -9992,9 +10099,11 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { return PM3_EINVARG; } - // Step 1: Read config + // Step 1: Read config - reuse the block already read while auto-probing the wakeup. uint8_t config[MFBLOCK_SIZE]; - if (gdm_read_config(wakeup_type, auth_cmd, key, config) != PM3_SUCCESS) { + if (have_probe) { + memcpy(config, probe_cfg, MFBLOCK_SIZE); + } else if (gdm_read_config(wakeup_type, auth_cmd, key, config) != PM3_SUCCESS) { return PM3_EFAILED; } bool changed = false; @@ -10009,21 +10118,28 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { } \ } - if (gen1_flag != -1) { - if (gen1_flag == 1) { - if (config[0] != 0x7A || config[1] != 0xFF) { - config[0] = 0x7A; - config[1] = 0xFF; - changed = true; - PrintAndLogEx(INFO, "Set Gen1 mode to on"); - } - } else { - if (config[0] != 0x85 || config[1] != 0x00) { - config[0] = 0x85; - config[1] = 0x00; - changed = true; - PrintAndLogEx(INFO, "Set Gen1 mode to off"); - } + if (wakestyle == WS_OFF) { + if (config[0] != 0x85 || config[1] != 0x00) { + config[0] = 0x85; + config[1] = 0x00; + changed = true; + PrintAndLogEx(INFO, "Set magic wakeup to off (backdoor sealed)"); + PrintAndLogEx(WARNING, "Both gdm and gen1a wakeups are now disabled; only WUPA magic auth remains"); + } + } else if (wakestyle == WS_GDM || wakestyle == WS_GEN1A) { + if (config[0] != 0x7A || config[1] != 0xFF) { + config[0] = 0x7A; + config[1] = 0xFF; + changed = true; + PrintAndLogEx(INFO, "Set magic wakeup to on"); + } + uint8_t style_byte = (wakestyle == WS_GDM) ? 0x85 : 0x00; + if (config[2] != style_byte) { + config[2] = style_byte; + changed = true; + PrintAndLogEx(INFO, "Set wakeup style to %s", (wakestyle == WS_GDM) ? "gdm alt (20/23)" : "gen1a (40/43)"); + PrintAndLogEx(WARNING, "After this write the card answers " _YELLOW_("--%s") " only, not the other one", + (wakestyle == WS_GDM) ? "gdm" : "gen1a"); } } @@ -10060,7 +10176,7 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmsetblk", "Set public block data on a GDM card\n" - "By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override.\n" + "With no wakeup flag it auto-detects the card's access mode (gen1a, gdm alt, or WUPA magic auth).\n" "`--force` param is used to override warnings like bad ACL writes.\n" " if not specified, it will exit if detected", "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f\n" @@ -10072,9 +10188,9 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { arg_int1(NULL, "blk", "", "public block number"), arg_str1("d", "data", "", "bytes to write, 16 hex bytes"), arg_str0("k", "key", "", "key, 6 hex bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_lit0(NULL, "force", "override warnings"), arg_param_end }; @@ -10106,11 +10222,17 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) { return PM3_EINVARG; } - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a public-block read of the target block. + gdm_wakeup_t gw; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + ISO14443A_CMD_READBLOCK, b, false, "hf mf gdmsetblk", + &gw, NULL, NULL); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); uint8_t blockno = (uint8_t)b; @@ -10156,7 +10278,7 @@ static int CmdHF14AGen4_GDM_SetHidBlk(const char *Cmd) { CLIParserInit(&ctx, "hf mf gdmsethidblk", "Write hidden block data on a GDM card.\n" "Hidden blocks 0-7 map to the card's hidden sector area.\n" - "By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override.\n" + "With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.\n" "`--force` param is used to override warnings like bad BCC or ACL writes.\n" " if not specified, it will exit if detected", "hf mf gdmsethidblk --blk 0 -d 880494716904EA0C2394510800000000\n" @@ -10169,9 +10291,9 @@ static int CmdHF14AGen4_GDM_SetHidBlk(const char *Cmd) { arg_int1(NULL, "blk", "", "hidden block number (0-7)"), arg_str1("d", "data", "", "bytes to write, 16 hex bytes"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_lit0(NULL, "force", "override warnings"), arg_param_end }; @@ -10206,11 +10328,18 @@ static int CmdHF14AGen4_GDM_SetHidBlk(const char *Cmd) { } // --- validate key length + resolve wakeup mode --- - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a hidden-block read of the target block; hidden + // writes require a gen1a/gdm backdoor, which the 0x38 probe naturally selects for. + gdm_wakeup_t gw; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + MIFARE_MAGIC_GDM_READBLOCK, b, true, "hf mf gdmsethidblk", + &gw, NULL, NULL); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); uint8_t blockno = (uint8_t)b; @@ -10358,8 +10487,8 @@ static int CmdHF14AGen4_GDM_GetHidBlk(const char *Cmd) { arg_int0(NULL, "sec", "", "sector to read"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -10391,8 +10520,8 @@ static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { arg_int0(NULL, "sec", "", "sector to read"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -10413,7 +10542,8 @@ static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) { static int CmdHF14AGen4_GDM_SetUid(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmsetuid", - "Set UID on a GDM card", + "Set UID on a GDM card.\n" + "With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "hf mf gdmsetuid -u 01020304\n" "hf mf gdmsetuid -u 01020304050607 --gen1a" ); @@ -10421,9 +10551,9 @@ static int CmdHF14AGen4_GDM_SetUid(const char *Cmd) { arg_param_begin, arg_str1("u", "uid", "", "UID to set (4 or 7 hex bytes)"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_lit0(NULL, "f3d", "use F3 perso mode (writes to hidden block 1 instead of 0)"), arg_param_end }; @@ -10448,11 +10578,19 @@ static int CmdHF14AGen4_GDM_SetUid(const char *Cmd) { return PM3_EINVARG; } - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a hidden-block read; gdmsetuid writes hidden data, + // so it always requires a gen1a/gdm backdoor (a WUPA-only card is rejected here + // before any write, avoiding the config-written/data-not-written half-brick). + gdm_wakeup_t gw; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + MIFARE_MAGIC_GDM_READBLOCK, 0, true, "hf mf gdmsetuid", + &gw, NULL, NULL); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); // Step 1: Read Config uint8_t config[MFBLOCK_SIZE]; @@ -10571,19 +10709,22 @@ static int CmdHF14AGen4_GDM_SetUid(const char *Cmd) { static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmwipe", - "Wipe a GDM card to factory defaults", + "Wipe a GDM card to factory defaults.\n" + "With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "hf mf gdmwipe --gdm" ); void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_lit0("a", "all", "wipe 4K card (40 sectors) instead of 1K card (16 sectors)"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, false); + // every arg is optional here, so allow a bare `hf mf gdmwipe` - otherwise the + // no-flag auto-detect path is unreachable and the command just prints help. + CLIExecWithReturn(ctx, Cmd, argtable, true); int keylen = 0; uint8_t key[6] = {0}; @@ -10595,14 +10736,34 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { bool wipe_4k = arg_get_lit(ctx, 5); CLIParserFree(ctx); - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a hidden-block read; gdmwipe rewrites hidden blocks, + // so it always requires a gen1a/gdm backdoor (WUPA-only cards are rejected before any + // write). + gdm_wakeup_t gw; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + MIFARE_MAGIC_GDM_READBLOCK, 0, true, "hf mf gdmwipe", + &gw, NULL, NULL); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); // Step 1: Write Config uint8_t standard_config[MFBLOCK_SIZE] = {0x7A, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x08}; + + // Keep the card's existing backdoor wakeup style (config byte 2: 0x85 = GDM 20/23, + // anything else = gen1a 40/43). The standard config hardcodes gen1a style, so on a + // GDM-style card writing it here would switch the card out from under us and every + // block write below would fail with `wupGDM1 error` - config wiped, data untouched. + uint8_t cur_config[MFBLOCK_SIZE] = {0}; + if (gdm_read_config(wakeup_type, auth_cmd, key, cur_config) == PM3_SUCCESS) { + standard_config[2] = cur_config[2]; + } else { + PrintAndLogEx(WARNING, "Could not read current config, keeping the default wakeup style"); + } + mf_writeblock_ex_t config_payload = { .wakeup = wakeup_type, .auth_cmd = auth_cmd, @@ -10633,6 +10794,9 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { }; memcpy(write_payload.key, key, 6); + int failed_blocks = 0; + int total_blocks = 0; + for (int sec = 0; sec < max_sector; sec++) { int first_blk = mfFirstBlockOfSector(sec); int num_blks = mfNumBlocksPerSector(sec); @@ -10653,7 +10817,9 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_WRITEBL_EX, (uint8_t *)&write_payload, sizeof(write_payload)); - WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX, &resp, 1500); + if (WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX, &resp, 1500) == false || resp.status != PM3_SUCCESS) { + failed_blocks++; + } // Hidden block writes write_payload.write_cmd = MIFARE_MAGIC_GDM_WRITEBLOCK; // 0xA8 @@ -10663,28 +10829,43 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_WRITEBL_EX, (uint8_t *)&write_payload, sizeof(write_payload)); - WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX, &resp, 1500); + if (WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX, &resp, 1500) == false || resp.status != PM3_SUCCESS) { + failed_blocks++; + } + total_blocks += 2; } PrintAndLogEx(INFO, "Wiping sector %d...", sec); } - PrintAndLogEx(SUCCESS, "Wipe completed!"); - return PM3_SUCCESS; + // Don't claim success when the card NAKed every write - that hid a wiped config with + // completely untouched data blocks. + if (failed_blocks == 0) { + PrintAndLogEx(SUCCESS, "Wipe completed!"); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Wipe incomplete - " _RED_("%d") " of %d block writes failed", failed_blocks, total_blocks); + if (failed_blocks == total_blocks) { + PrintAndLogEx(HINT, "Hint: the card did not accept any data write. Check that the wakeup still matches"); + PrintAndLogEx(HINT, " the card's config (`" _YELLOW_("hf mf gdmgetcfg") "`), then retry"); + } + return PM3_EFAILED; } static int CmdHF14AGen4_GDM_SetSig(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf gdmsetsig", - "Set MFC EV1 signature on a GDM card", + "Set MFC EV1 signature on a GDM card.\n" + "With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "hf mf gdmsetsig -s <64 hex chars>" ); void *argtable[] = { arg_param_begin, arg_str1("s", "sig", "", "32-byte signature (64 hex characters)"), arg_str0("k", "key", "", "key 6 bytes (only for --wupa mode)"), - arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup (default)"), - arg_lit0(NULL, "gen1a", "use gen1a (40/43) magic wakeup"), - arg_lit0(NULL, "wupa", "use regular wakeup (WUPA + magic auth with key)"), + arg_lit0(NULL, "gdm", "access: force gdm alt (20/23) magic wakeup"), + arg_lit0(NULL, "gen1a", "access: force gen1a (40/43) magic wakeup"), + arg_lit0(NULL, "wupa", "access: force regular wakeup (WUPA + magic auth with key)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -10707,11 +10888,18 @@ static int CmdHF14AGen4_GDM_SetSig(const char *Cmd) { return PM3_EINVARG; } - uint8_t wakeup_type = 0; - uint8_t auth_cmd = 0; - if (gdm_resolve_wakeup(gdm, gen1a, wupa, keylen, &wakeup_type, &auth_cmd) != PM3_SUCCESS) { - return PM3_EINVARG; + // Auto-detect wakeup by probing a hidden-block read (block 5, where the signature + // lands); gdmsetsig writes hidden blocks, so it always requires a gen1a/gdm backdoor. + gdm_wakeup_t gw; + int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, + MIFARE_MAGIC_GDM_READBLOCK, 5, true, "hf mf gdmsetsig", + &gw, NULL, NULL); + if (wres != PM3_SUCCESS) { + return wres; } + uint8_t wakeup_type = gw.wakeup_type; + uint8_t auth_cmd = gw.auth_cmd; + memcpy(key, gw.key, sizeof(key)); // Step 1: Write signature part 1 (block 5) mf_writeblock_ex_t write_payload = { diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index 7638788e7..cdec39eed 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -222,6 +222,7 @@ const static vocabulary_t vocabulary[] = { { 0, "hf 15 writeafi" }, { 0, "hf 15 writedsfid" }, { 0, "hf 15 csetuid" }, + { 0, "hf 15 cfinalize" }, { 1, "hf aliro help" }, { 1, "hf aliro list" }, { 0, "hf aliro info" }, @@ -257,12 +258,12 @@ const static vocabulary_t vocabulary[] = { { 1, "hf felica help" }, { 1, "hf felica list" }, { 0, "hf felica info" }, - { 0, "hf felica seacauth1" }, { 0, "hf felica raw" }, { 0, "hf felica rdbl" }, { 0, "hf felica reader" }, { 0, "hf felica sniff" }, { 0, "hf felica wrbl" }, + { 0, "hf felica seacauth1" }, { 0, "hf felica dump" }, { 0, "hf felica discnodes" }, { 0, "hf felica sim" }, @@ -676,7 +677,11 @@ const static vocabulary_t vocabulary[] = { { 0, "hw bootloader" }, { 1, "hw connect" }, { 0, "hw dbg" }, + { 0, "hw fpga" }, { 0, "hw fpgaoff" }, + { 0, "hw ant_pm5" }, + { 0, "hw qc_pm5" }, + { 0, "hw factorydata" }, { 0, "hw lcd" }, { 0, "hw lcdreset" }, { 0, "hw ping" }, @@ -1065,8 +1070,6 @@ const static vocabulary_t vocabulary[] = { { 0, "script run data_mf_eml2bin.lua" }, { 0, "script run data_mf_eml2html.lua" }, { 0, "script run data_mfu_bin2eml.lua" }, - { 0, "script run example_cmdline.lua" }, - { 0, "script run example_parameters.lua" }, { 0, "script run hf_14a_aztek.lua" }, { 0, "script run hf_14a_i2crevive.lua" }, { 0, "script run hf_14a_protectimus_nfc.lua" }, @@ -1117,6 +1120,7 @@ const static vocabulary_t vocabulary[] = { { 0, "script run lf_em_tearoff_protect.lua" }, { 0, "script run lf_hid_bulkclone.lua" }, { 0, "script run lf_hid_bulkclone_v2.lua" }, + { 0, "script run lf_ht2_paxton.lua" }, { 0, "script run lf_ident_json.lua" }, { 0, "script run lf_ioprox_bulkclone.lua" }, { 0, "script run lf_t55xx_chk.lua" }, @@ -1131,13 +1135,6 @@ const static vocabulary_t vocabulary[] = { { 0, "script run ntag_clean.lua" }, { 0, "script run ntag_getsig.lua" }, { 0, "script run ntag_hammertime.lua" }, - { 0, "script run data_tracetest.lua" }, - { 0, "script run hf_read.lua" }, - { 0, "script run lf_t55xx_defaultask.lua" }, - { 0, "script run lf_t55xx_defaultbi.lua" }, - { 0, "script run lf_t55xx_defaultfsk.lua" }, - { 0, "script run lf_t55xx_defaultpsk.lua" }, - { 0, "script run lf_t55xx_writetest.lua" }, { 0, "script run example.cmd" }, { 0, "script run rdv4_init_extflash.cmd" }, { 0, "script run test_psk_clone.cmd" }, diff --git a/doc/commands.json b/doc/commands.json index 6e0e1657c..5c1cf6a2a 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -1891,20 +1891,35 @@ ], "usage": "hf 14b wrbl [-h] [-b ] -d [--512] [--4k] [--sb] [--force]" }, + "hf 15 cfinalize": { + "command": "hf 15 cfinalize", + "description": "Finalize a magic ISO15693 'V3' tag. This operation is irreversible. After finalize the configuration area is erased and the UID can no longer be changed. Set the UID with `hf 15 csetuid --v3` first, then lock it in with this command.", + "notes": [ + "hf 15 cfinalize -y" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-y, --yes Confirm the irreversible finalize operation" + ], + "usage": "hf 15 cfinalize [-hy]" + }, "hf 15 csetuid": { "command": "hf 15 csetuid", - "description": "Set UID for magic Chinese card (only works with such cards)", + "description": "Set UID for magic Chinese card (only works with such cards) For magic 'V3' tags this writes the UID configuration only and is repeatable; run `hf 15 cfinalize` afterwards to lock the UID permanently.", "notes": [ "hf 15 csetuid -u E011223344556677 -> use gen1 command", - "hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command" + "hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command", + "hf 15 csetuid -u E011223344556677 --v3 -> use gen3 (V3) magic tag" ], "offline": false, "options": [ "-h, --help This help", "-u, --uid UID, 8 hex bytes", - "-2, --v2 Use gen2 magic command" + "-2, --v2 Use gen2 magic command", + "-3, --v3 Use gen3 (V3) magic tag (repeatable, needs cfinalize)" ], - "usage": "hf 15 csetuid [-h2] -u " + "usage": "hf 15 csetuid [-h23] -u " }, "hf 15 demod": { "command": "hf 15 demod", @@ -3020,7 +3035,7 @@ }, "hf felica help": { "command": "hf felica help", - "description": "----------- ----------------------- General ----------------------- help This help list List ISO 18092/FeliCa history ----------- ----------------------- Operations ----------------------- ----------- ----------------------- FeliCa Standard ----------------------- ----------- ----------------------- FeliCa Light ----------------------- --------------------------------------------------------------------------------------- hf felica list available offline: yes Alias of `trace list -t felica` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "----------- ----------------------- General ----------------------- help This help list List ISO 18092/FeliCa history ----------- ----------------------- Operations ----------------------- ----------- ----------------------- FeliCa SEAC ----------------------- ----------- ----------------------- FeliCa Standard ----------------------- ----------- ----------------------- FeliCa Light ----------------------- --------------------------------------------------------------------------------------- hf felica list available offline: yes Alias of `trace list -t felica` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf felica list --frame -> show frame delay times", "hf felica list -1 -> use trace buffer" @@ -3248,17 +3263,22 @@ ], "usage": "hf felica scsvcode [-h] [-r ] [--idm ]" }, - "hf felica seacinfo": { - "command": "hf felica seacinfo", - "description": "Get info about FeliCa SEAC cards", + "hf felica seacauth1": { + "command": "hf felica seacauth1", + "description": "Send FeliCa SEAC Authentication1", "notes": [ - "hf felica seacinfo" + "hf felica seacauth1", + "hf felica seacauth1 --selector 0F", + "hf felica seacauth1 --challenge 0001020304050607", + "hf felica seacauth1 -s 0F -c FFFFFFFFFFFFFFFF" ], "offline": false, "options": [ - "-h, --help This help" + "-h, --help This help", + "-s, --selector selector, 1 byte (default 01)", + "-c, --challenge Challenge1a, 8 bytes (default all zero)" ], - "usage": "hf felica seacinfo [-h]" + "usage": "hf felica seacauth1 [-h] [-s ] [-c ]" }, "hf felica sim": { "command": "hf felica sim", @@ -4835,16 +4855,30 @@ }, "hf iclass sam": { "command": "hf iclass sam", - "description": "hf iclass sam - HID SAM operations Secure-channel subcommands: Legacy PACS-extraction flags (no subcommand, applied to hf iclass sam directly): --info get SAM version + serial number (also warms up the SAM) -d, --data DER-encoded SAMCommand to send (raw, no SC) -s, --snmp --data is in SNMP format without the A0/94 headers -p, --prevent fake the e-purse update during PACS extraction --break stop tag interaction at nr-mac (for SIO extract) -f, --file emulate from a dump file instead of a real card -n, --nodetect skip card detect + SetDetectedCardInfo -k, --keep keep the field active after the command -t, --tlv decode the response as TLV --shallow shallow modulation -v, --verbose verbose output Examples: hf iclass sam extract PACS via SAM (defaults) hf iclass sam --info get SAM version + serial (warmup ping) hf iclass sam scopen open Artemis secure channel hf iclass sam scsend --payload 8200 send wrapped SAMCommand hf iclass sam scclose terminate the SC session ======================================================================================= hf ict { ICT MFC/DESfire RFIDs... } --------------------------------------------------------------------------------------- hf ict help available offline: yes help This help list List ICT history reader Act like an IS14443-a reader --------------------------------------------------------------------------------------- hf ict credential available offline: no Read ICT sector from tag and decode", + "description": "Extract PACS via a HID SAM", "notes": [ - "hf ict credential" + "hf iclass sam", + "hf iclass sam -p -d a005a103800104 -> get PACS data, prevent epurse update", + "hf iclass sam --break -> get Nr-MAC for extracting encrypted SIO", + "hf iclass sam -f hf-iclass-dump.bin -> emulate card from dump file to SAM", + "hf iclass sam --info -> get SAM version + serial (also warms up the SAM)" ], "offline": false, "options": [ "-h, --help This help", - "-v, --verbose verbose output" + "-v, --verbose verbose output", + "-k, --keep keep the field active after command executed", + "-n, --nodetect skip selecting the card and sending card details to SAM", + "-t, --tlv decode TLV", + "--break stop tag interaction on nr-mac", + "-p, --prevent fake epurse update", + "--shallow shallow mod", + "-d, --data DER encoded command to send to SAM", + "-s, --snmp data is in snmp format without headers", + "--info get SAM infos (version, serial number)", + "-f, --file dump file to emulate to SAM instead of a real card" ], - "usage": "hf ict credential [-hv]" + "usage": "hf iclass sam [-hvkntps] [--break] [--shallow] [-d ]... [--info] [-f ]" }, "hf iclass sim": { "command": "hf iclass sim", @@ -5003,6 +5037,19 @@ ], "usage": "hf iclass wrbl [-hv@] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow]" }, + "hf ict help": { + "command": "hf ict help", + "description": "help This help list List ICT history reader Act like an IS14443-a reader --------------------------------------------------------------------------------------- hf ict credential available offline: no Read ICT sector from tag and decode", + "notes": [ + "hf ict credential" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-v, --verbose verbose output" + ], + "usage": "hf ict credential [-hv]" + }, "hf ict info": { "command": "hf ict info", "description": "Get info from ICT encoded credential tags (MIFARE Classic / DESfire)", @@ -6118,7 +6165,7 @@ }, "hf mf gdmgetblk": { "command": "hf mf gdmgetblk", - "description": "Read public block(s) from a GDM card", + "description": "Read public block(s) from a GDM card. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", "notes": [ "hf mf gdmgetblk --blk 0", "hf mf gdmgetblk --sec 1 --gdm" @@ -6129,15 +6176,15 @@ "--blk block to read", "--sec sector to read", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgetblk [-h] [--blk ] [--sec ] [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmgetcfg": { "command": "hf mf gdmgetcfg", - "description": "Get configuration data from a GDM card. By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override.", + "description": "Get configuration data from a GDM card. With no wakeup flag it auto-detects the card's access mode (tries WUPA magic auth, then gen1a, then gdm alt). Use `--gdm`/`--gen1a`/`--wupa` to force one.", "notes": [ "hf mf gdmgetcfg", "hf mf gdmgetcfg --gen1a", @@ -6147,15 +6194,15 @@ "options": [ "-h, --help This help", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgetcfg [-h] [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmgethidblk": { "command": "hf mf gdmgethidblk", - "description": "Read hidden block(s) from a GDM card", + "description": "Read hidden block(s) from a GDM card. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", "notes": [ "hf mf gdmgethidblk --blk 0", "hf mf gdmgethidblk --sec 1 --gdm" @@ -6166,9 +6213,9 @@ "--blk block to read", "--sec sector to read", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgethidblk [-h] [--blk ] [--sec ] [-k ] [--gdm] [--gen1a] [--wupa]" }, @@ -6187,7 +6234,7 @@ }, "hf mf gdmsetblk": { "command": "hf mf gdmsetblk", - "description": "Set public block data on a GDM card By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override. `--force` param is used to override warnings like bad ACL writes. if not specified, it will exit if detected", + "description": "Set public block data on a GDM card With no wakeup flag it auto-detects the card's access mode (gen1a, gdm alt, or WUPA magic auth). `--force` param is used to override warnings like bad ACL writes. if not specified, it will exit if detected", "notes": [ "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f", "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f --gen1a", @@ -6199,19 +6246,20 @@ "--blk public block number", "-d, --data bytes to write, 16 hex bytes", "-k, --key key, 6 hex bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)", + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)", "--force override warnings" ], "usage": "hf mf gdmsetblk [-h] --blk -d [-k ] [--gdm] [--gen1a] [--wupa] [--force]" }, "hf mf gdmsetcfg": { "command": "hf mf gdmsetcfg", - "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back.", + "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt). Note the two groups below are different things: --gdm / --gen1a / --wupa how THIS command talks to the card (access, not stored) --wakestyle / --cuid / ... what gets STORED in the card's config block", "notes": [ "hf mf gdmsetcfg -d 850000000000000000005A5A00000008", - "hf mf gdmsetcfg --cuid on --gen1 on", + "hf mf gdmsetcfg --cuid on --wakestyle gen1a", + "hf mf gdmsetcfg --wakestyle off", "hf mf gdmsetcfg --shadow off --sigsec off --wupa -k FFFFFFFFFFFF" ], "offline": false, @@ -6219,22 +6267,22 @@ "-h, --help This help", "-d, --data raw bytes to write, 16 hex bytes", "-k, --key key 6 bytes (only for regular wakeup)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)", - "--gen1 Gen1 mode (7A FF)", - "--cuid Gen2/CUID mode", - "--cl2 CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>` to set a valid UID", - "--shadow Shadow mode", - "--magicauth Magic auth", - "--statenc Static encrypted nonce", - "--sigsec Signature sector" + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)", + "--cuid config: Gen2/CUID mode", + "--cl2 config: CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>`", + "--shadow config: Shadow mode", + "--magicauth config: Magic auth (what --wupa uses)", + "--statenc config: Static encrypted nonce", + "--sigsec config: Signature sector", + "--wakestyle config: backdoor - gdm (7AFF85), gen1a (7AFF00), or off (8500, seal)" ], - "usage": "hf mf gdmsetcfg [-h] [-d ] [-k ] [--gdm] [--gen1a] [--wupa] [--gen1 ] [--cuid ] [--cl2 ] [--shadow ] [--magicauth ] [--statenc ] [--sigsec ]" + "usage": "hf mf gdmsetcfg [-h] [-d ] [-k ] [--gdm] [--gen1a] [--wupa] [--cuid ] [--cl2 ] [--shadow ] [--magicauth ] [--statenc ] [--sigsec ] [--wakestyle ]" }, "hf mf gdmsethidblk": { "command": "hf mf gdmsethidblk", - "description": "Write hidden block data on a GDM card. Hidden blocks 0-7 map to the card's hidden sector area. By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override. `--force` param is used to override warnings like bad BCC or ACL writes. if not specified, it will exit if detected", + "description": "Write hidden block data on a GDM card. Hidden blocks 0-7 map to the card's hidden sector area. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected. `--force` param is used to override warnings like bad BCC or ACL writes. if not specified, it will exit if detected", "notes": [ "hf mf gdmsethidblk --blk 0 -d 880494716904EA0C2394510800000000", "hf mf gdmsethidblk --blk 0 -d 880494716904EA0C2394510800000000 --gen1a", @@ -6247,16 +6295,16 @@ "--blk hidden block number (0-7)", "-d, --data bytes to write, 16 hex bytes", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)", + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)", "--force override warnings" ], "usage": "hf mf gdmsethidblk [-h] --blk -d [-k ] [--gdm] [--gen1a] [--wupa] [--force]" }, "hf mf gdmsetsig": { "command": "hf mf gdmsetsig", - "description": "Set MFC EV1 signature on a GDM card", + "description": "Set MFC EV1 signature on a GDM card. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "notes": [ "hf mf gdmsetsig -s <64 hex chars>" ], @@ -6265,15 +6313,15 @@ "-h, --help This help", "-s, --sig 32-byte signature (64 hex characters)", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)" + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmsetsig [-h] -s [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmsetuid": { "command": "hf mf gdmsetuid", - "description": "Set UID on a GDM card", + "description": "Set UID on a GDM card. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "notes": [ "hf mf gdmsetuid -u 01020304", "hf mf gdmsetuid -u 01020304050607 --gen1a" @@ -6283,16 +6331,16 @@ "-h, --help This help", "-u, --uid UID to set (4 or 7 hex bytes)", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)", + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)", "--f3d use F3 perso mode (writes to hidden block 1 instead of 0)" ], "usage": "hf mf gdmsetuid [-h] -u [-k ] [--gdm] [--gen1a] [--wupa] [--f3d]" }, "hf mf gdmwipe": { "command": "hf mf gdmwipe", - "description": "Wipe a GDM card to factory defaults", + "description": "Wipe a GDM card to factory defaults. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", "notes": [ "hf mf gdmwipe --gdm" ], @@ -6300,9 +6348,9 @@ "options": [ "-h, --help This help", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup (default)", - "--gen1a use gen1a (40/43) magic wakeup", - "--wupa use regular wakeup (WUPA + magic auth with key)", + "--gdm access: force gdm alt (20/23) magic wakeup", + "--gen1a access: force gen1a (40/43) magic wakeup", + "--wupa access: force regular wakeup (WUPA + magic auth with key)", "-a, --all wipe 4K card (40 sectors) instead of 1K card (16 sectors)" ], "usage": "hf mf gdmwipe [-ha] [-k ] [--gdm] [--gen1a] [--wupa]" @@ -8252,6 +8300,7 @@ "notes": [ "hf mfdes pc --key 00000000000000000000000000000000", "hf mfdes pc --key 00112233445566778899aabbccddeeff --rounds 4", + "hf mfdes pc --aid 123456 --key 00112233445566778899aabbccddeeff", "hf mfdes pc --key 00112233445566778899aabbccddeeff -c native -a" ], "offline": false, @@ -8261,9 +8310,10 @@ "-v, --verbose Verbose output", "-k, --key Key (AES-128, exactly 16 bytes)", "-r, --rounds Number of rounds (1..8), default 8", - "-c, --ccset Communication command set (default from `hf mfdes default`)" + "-c, --ccset Communication command set (default from `hf mfdes default`)", + "--aid Application ID (3 hex bytes, big endian)" ], - "usage": "hf mfdes pc [-hav] -k [-r ] [-c ]" + "usage": "hf mfdes pc [-hav] -k [-r ] [-c ] [--aid ]" }, "hf mfdes read": { "command": "hf mfdes read", @@ -10465,9 +10515,10 @@ "--bar bar style", "--mix mixed style", "--value values style", - "-v, --verbose verbose output" + "-v, --verbose verbose output", + "--rgb (PM5) mirror the tuning level on the antenna RGB LED" ], - "usage": "hf tune [-hv] [-n ] [--bar] [--mix] [--value]" + "usage": "hf tune [-hv] [-n ] [--bar] [--mix] [--value] [--rgb]" }, "hf vas decrypt": { "command": "hf vas decrypt", @@ -10652,6 +10703,21 @@ ], "usage": "hints [-h10]" }, + "hw ant_pm5": { + "command": "hw ant_pm5", + "description": "Control the antennal of pm5", + "notes": [ + "hw ant_pm5 --set -> Write the data of IO data register", + "hw ant_pm5 -m --set -> Write the data of IO map register" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-m, --map Write the IO map register", + "-s, --set Set PM5 antenna" + ], + "usage": "hw ant_pm5 [-hm] [-s ]" + }, "hw bootloader": { "command": "hw bootloader", "description": "Reboot Proxmark3 into bootloader mode", @@ -10725,9 +10791,23 @@ ], "usage": "hw decay [-h] [--ms ] [--us ]" }, - "hw fpgaoff": { - "command": "hw fpgaoff", - "description": "Turn of fpga and antenna field", + "hw factorydata": { + "command": "hw factorydata", + "description": "Get/Set the factory data for Device", + "notes": [ + "hw factorydata --load -> Write the factory data to device from file", + "hw factorydata -> Read and parse the factory data from device" + ], + "offline": false, + "options": [ + "-h, --help This help", + "--load Load factory data from file to device" + ], + "usage": "hw factorydata [-h] [--load ]" + }, + "hw fpga": { + "command": "hw fpga", + "description": "help This help ------------- ----------------------- Operation ----------------------- --------------------------------------------------------------------------------------- hw fpgaoff available offline: no Turn of fpga and antenna field", "notes": [ "hw fpgaoff" ], @@ -10792,6 +10872,18 @@ ], "usage": "hw ping [-h] [-l ]" }, + "hw qc_pm5": { + "command": "hw qc_pm5", + "description": "QC Test for the PM5", + "notes": [ + "hf qcpm5" + ], + "offline": false, + "options": [ + "-h, --help This help" + ], + "usage": "hw qcpm5 [-h]" + }, "hw readmem": { "command": "hw readmem", "description": "Reads processor flash memory into a file or views on console", @@ -14388,9 +14480,10 @@ "--bar bar style", "--mix mixed style", "--value values style", - "-v, --verbose verbose output" + "-v, --verbose verbose output", + "--rgb (PM5) mirror the tuning level on the antenna RGB LED" ], - "usage": "lf tune [-hv] [-n ] [-q ] [-f ] [--bar] [--mix] [--value]" + "usage": "lf tune [-hv] [-n ] [-q ] [-f ] [--bar] [--mix] [--value] [--rgb]" }, "lf viking clone": { "command": "lf viking clone", @@ -16023,8 +16116,8 @@ } }, "metadata": { - "commands_extracted": 896, + "commands_extracted": 901, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2026-07-30T14:44:57+00:00" + "extracted_on": "2026-08-22T14:19:35+00:00" } } diff --git a/doc/commands.md b/doc/commands.md index 07bed6008..612340856 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -281,6 +281,7 @@ Check column "offline" for their availability. |`hf 15 writeafi `|N |`Writes the AFI on an ISO-15693 tag` |`hf 15 writedsfid `|N |`Writes the DSFID on an ISO-15693 tag` |`hf 15 csetuid `|N |`Set UID for magic card` +|`hf 15 cfinalize `|N |`Finalize a magic V3 tag (irreversible)` ### hf aliro @@ -364,12 +365,12 @@ Check column "offline" for their availability. |`hf felica help `|Y |`This help` |`hf felica list `|Y |`List ISO 18092/FeliCa history` |`hf felica info `|N |`Tag information` -|`hf felica seacinfo `|N |`FeliCa SEAC tag information` |`hf felica raw `|N |`Send raw hex data to tag` |`hf felica rdbl `|N |`read block data from authentication-not-required Service.` |`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` |`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` |`hf felica wrbl `|N |`write block data to an authentication-not-required Service.` +|`hf felica seacauth1 `|N |`FeliCa SEAC Authentication1` |`hf felica dump `|N |`Wait for and try dumping FeliCa` |`hf felica discnodes `|N |`discover Area Code and Service Code nodes.` |`hf felica sim `|N |`Emulate FeliCa Standard from dump file` @@ -537,7 +538,7 @@ Check column "offline" for their availability. |`hf iclass decrypt `|Y |`Decrypt given block data or tag dump file` |`hf iclass managekeys `|Y |`Manage keys to use with iclass commands` |`hf iclass permutekey `|Y |`Permute function from 'heart of darkness' paper` -|`hf iclass sam `|N |`SAM ops: PACS extract + secure channel (scopen/scsend/scclose)` +|`hf iclass sam `|N |`Extract PACS from a HID SAM` ### hf ict @@ -1007,7 +1008,11 @@ Check column "offline" for their availability. |`hw bootloader `|N |`Reboot into bootloader mode` |`hw connect `|Y |`Connect to the device via serial port` |`hw dbg `|N |`Set device side debug level` +|`hw fpga `|N |`Fpga commands` |`hw fpgaoff `|N |`Turn off FPGA on device` +|`hw ant_pm5 `|N |`Control the antennal of pm5` +|`hw qc_pm5 `|N |`Perform QC test for the PM5` +|`hw factorydata `|N |`Get/Set the factory data for Device` |`hw lcd `|N |`Send command/data to LCD` |`hw lcdreset `|N |`Hardware reset LCD` |`hw ping `|N |`Test if the Proxmark3 is responsive` From a0ad7dbeec75d9b02523c635078e48e75bf1b2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=90=E6=AD=AA?= Date: Sat, 22 Aug 2026 22:50:54 +0800 Subject: [PATCH 3/5] Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into 20260819-gdmfix --- doc/commands.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/commands.json b/doc/commands.json index adf033844..425709a23 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -16139,14 +16139,8 @@ } }, "metadata": { -<<<<<<< HEAD "commands_extracted": 901, "extracted_by": "PM3Help2JSON v1.00", "extracted_on": "2026-08-22T14:19:35+00:00" -======= - "commands_extracted": 902, - "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2026-08-21T18:43:14+00:00" ->>>>>>> b4c4edd7c94a989108cacaaaf73805a28a6c217c } } From a1a400e0be9c0e0c909562855418df657160fe8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=90=E6=AD=AA?= Date: Sun, 30 Aug 2026 06:20:59 +0800 Subject: [PATCH 4/5] style: content clean up --- client/src/cmdhfmf.c | 71 ++++++++++---------------------------------- doc/commands.json | 2 +- 2 files changed, 16 insertions(+), 57 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 672ffc4ec..9dc294cf7 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -9752,13 +9752,7 @@ static const char *gdm_wakeup_name(const gdm_wakeup_t *w) { return "gdm alt (20/23)"; } -// Build the list of wakeup attempts a read command should try. With an explicit -// mode (--gdm/--gen1a/--wupa, or a key) there is exactly one attempt. With nothing -// specified, returns all three access paths (gen1a, gdm alt, WUPA + magic auth with -// an all-zero key) so a card that only enables one of them is still reachable. -// `prefer_auth` puts WUPA magic auth first - use it for config reads (magic auth can -// read the config block); leave it false for data-block reads, where the backdoor -// wakeups are tried first (magic auth usually cannot read normal/hidden blocks). +// Build the wakeup attempts to try. Explicit --gdm/--gen1a/--wupa (or a key) => 1 attempt; static int gdm_wakeup_attempts(bool gdm, bool gen1a, bool wupa, const uint8_t *key, int keylen, bool prefer_auth, gdm_wakeup_t attempts[3], int *count) { if (gdm || gen1a || wupa || keylen > 0) { @@ -9823,21 +9817,7 @@ static int gdm_pick_wakeup(uint8_t read_cmd, int probe_blk, const gdm_wakeup_t * return -1; } -// Resolve which wakeup a WRITE command should use, by probing with a matching READ. -// probe_read_cmd/probe_blk : the read used to test reachability - config (0xE0), -// public block (0x30), or hidden block (0x38). Use the -// read that matches what the command actually writes, so -// a wakeup that cannot reach the write target is rejected -// during the (read-only) probe instead of half-writing. -// needs_backdoor : true for hidden/mixed writes a WUPA-only card cannot do. -// On probe failure it prints a "enable a backdoor" hint and -// returns an error WITHOUT touching the card. -// out_probe_data/out_have_probe (nullable) : receive the block read during a successful -// auto-probe, letting the caller reuse it (e.g. setcfg reusing -// the config it just read). *out_have_probe is false when the -// wakeup was given explicitly (no probe was performed). -// With an explicit wakeup (--gdm/--gen1a/--wupa or a key) there is no probe and behaviour -// is unchanged: exactly the chosen wakeup is returned. +// Probe with a matching READ to select the WRITE wakeup mode, avoiding partial writes. static int gdm_resolve_for_write(bool gdm, bool gen1a, bool wupa, const uint8_t *key, int keylen, uint8_t probe_read_cmd, int probe_blk, @@ -9849,8 +9829,7 @@ static int gdm_resolve_for_write(bool gdm, bool gen1a, bool wupa, } bool explicit_mode = (gdm || gen1a || wupa || keylen > 0); - // config reads can use magic auth, so try WUPA first there; for data/hidden reads try - // the backdoors first (magic auth usually cannot reach normal/hidden blocks). + // config reads can use magic auth; data/hidden reads usually cannot, so try backdoors first bool prefer_auth = (probe_read_cmd == MIFARE_MAGIC_GDM_READ_CFG); gdm_wakeup_t attempts[3]; @@ -9859,7 +9838,7 @@ static int gdm_resolve_for_write(bool gdm, bool gen1a, bool wupa, return PM3_EINVARG; } - // Explicit wakeup: do not probe, keep legacy behaviour (single attempt, may fail at write). + // Explicit wakeup: no probe, keep legacy single-attempt behaviour. if (explicit_mode) { *out_w = attempts[0]; return PM3_SUCCESS; @@ -9869,8 +9848,7 @@ static int gdm_resolve_for_write(bool gdm, bool gen1a, bool wupa, int idx = gdm_pick_wakeup(probe_read_cmd, probe_blk, attempts, n_attempts, buf); if (idx < 0) { if (needs_backdoor) { - // Distinguish a WUPA-only (sealed) card from an unreachable one: can WUPA magic - // auth still read the config block? If so, the card is fine but lacks a backdoor. + // WUPA magic auth still reads config gdm_wakeup_t w = { .wakeup_type = MF_WAKE_WUPA, .auth_cmd = MIFARE_MAGIC_GDM_AUTH_KEY }; memset(w.key, 0, sizeof(w.key)); if (gdm_try_read(MIFARE_MAGIC_GDM_READ_CFG, 0, &w, buf) == PM3_SUCCESS) { @@ -9967,10 +9945,7 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { "Can either write raw 16 bytes (-d) or configure specific flags.\n" "If flags are provided, it will read the config, update flags, and write it back.\n" "With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).\n" - "\n" - "Note the two groups below are different things:\n" - " --gdm / --gen1a / --wupa how THIS command talks to the card (access, not stored)\n" - " --wakestyle / --cuid / ... what gets STORED in the card's config block", + "`access:` flags select how this command talks to the card; `config:` flags change what is stored.", "hf mf gdmsetcfg -d 850000000000000000005A5A00000008\n" "hf mf gdmsetcfg --cuid on --wakestyle gen1a\n" "hf mf gdmsetcfg --wakestyle off\n" @@ -10014,10 +9989,7 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { int statenc_flag = gdm_arg_onoff(ctx, 10); int sigsec_flag = gdm_arg_onoff(ctx, 11); - // Backdoor selector. Sets config byte 0-1 (backdoor on 7AFF / off 8500) and, when - // enabling, byte 2 (style: 85 = GDM 20/23, 00 = gen1a 40/43). This is the only way to - // toggle the backdoor - there is no separate on/off flag. - // gdm -> 7AFF85 gen1a -> 7AFF00 off -> 8500 (byte 2 left as-is) + // Backdoor selector, the only control for it: gdm -> 7AFF85, gen1a -> 7AFF00, off -> 8500. enum { WS_NONE, WS_GDM, WS_GEN1A, WS_OFF } wakestyle = WS_NONE; struct arg_str *ws = arg_get_str(ctx, 12); if (ws->count > 0) { @@ -10041,8 +10013,7 @@ static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd) { return PM3_EINVARG; } - // Auto-detect wakeup by probing a config read; the config block is reachable via WUPA - // magic auth as well as either backdoor, so no backdoor is required here. + // Auto-detect wakeup by probing a config read (reachable via magic auth or either backdoor). gdm_wakeup_t gw; uint8_t probe_cfg[MFBLOCK_SIZE] = {0}; bool have_probe = false; @@ -10328,8 +10299,7 @@ static int CmdHF14AGen4_GDM_SetHidBlk(const char *Cmd) { } // --- validate key length + resolve wakeup mode --- - // Auto-detect wakeup by probing a hidden-block read of the target block; hidden - // writes require a gen1a/gdm backdoor, which the 0x38 probe naturally selects for. + // Auto-detect wakeup by probing a hidden-block read; hidden writes need a gen1a/gdm backdoor. gdm_wakeup_t gw; int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, MIFARE_MAGIC_GDM_READBLOCK, b, true, "hf mf gdmsethidblk", @@ -10578,9 +10548,7 @@ static int CmdHF14AGen4_GDM_SetUid(const char *Cmd) { return PM3_EINVARG; } - // Auto-detect wakeup by probing a hidden-block read; gdmsetuid writes hidden data, - // so it always requires a gen1a/gdm backdoor (a WUPA-only card is rejected here - // before any write, avoiding the config-written/data-not-written half-brick). + // Auto-detect wakeup by probing a hidden-block read; gdmsetuid needs a gen1a/gdm backdoor gdm_wakeup_t gw; int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, MIFARE_MAGIC_GDM_READBLOCK, 0, true, "hf mf gdmsetuid", @@ -10722,8 +10690,7 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { arg_lit0("a", "all", "wipe 4K card (40 sectors) instead of 1K card (16 sectors)"), arg_param_end }; - // every arg is optional here, so allow a bare `hf mf gdmwipe` - otherwise the - // no-flag auto-detect path is unreachable and the command just prints help. + // allow a bare `hf mf gdmwipe` (all args optional) so the no-flag auto-detect path works CLIExecWithReturn(ctx, Cmd, argtable, true); int keylen = 0; @@ -10737,8 +10704,7 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { CLIParserFree(ctx); // Auto-detect wakeup by probing a hidden-block read; gdmwipe rewrites hidden blocks, - // so it always requires a gen1a/gdm backdoor (WUPA-only cards are rejected before any - // write). + // so it needs a gen1a/gdm backdoor (WUPA-only cards are rejected before any write). gdm_wakeup_t gw; int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, MIFARE_MAGIC_GDM_READBLOCK, 0, true, "hf mf gdmwipe", @@ -10750,13 +10716,8 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { uint8_t auth_cmd = gw.auth_cmd; memcpy(key, gw.key, sizeof(key)); - // Step 1: Write Config + // Step 1: Write Config (gen1a + wupa + 4B UID) uint8_t standard_config[MFBLOCK_SIZE] = {0x7A, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x08}; - - // Keep the card's existing backdoor wakeup style (config byte 2: 0x85 = GDM 20/23, - // anything else = gen1a 40/43). The standard config hardcodes gen1a style, so on a - // GDM-style card writing it here would switch the card out from under us and every - // block write below would fail with `wupGDM1 error` - config wiped, data untouched. uint8_t cur_config[MFBLOCK_SIZE] = {0}; if (gdm_read_config(wakeup_type, auth_cmd, key, cur_config) == PM3_SUCCESS) { standard_config[2] = cur_config[2]; @@ -10837,8 +10798,7 @@ static int CmdHF14AGen4_GDM_Wipe(const char *Cmd) { PrintAndLogEx(INFO, "Wiping sector %d...", sec); } - // Don't claim success when the card NAKed every write - that hid a wiped config with - // completely untouched data blocks. + // report write failures instead of always printing "Wipe completed!" if (failed_blocks == 0) { PrintAndLogEx(SUCCESS, "Wipe completed!"); return PM3_SUCCESS; @@ -10888,8 +10848,7 @@ static int CmdHF14AGen4_GDM_SetSig(const char *Cmd) { return PM3_EINVARG; } - // Auto-detect wakeup by probing a hidden-block read (block 5, where the signature - // lands); gdmsetsig writes hidden blocks, so it always requires a gen1a/gdm backdoor. + // Auto-detect wakeup by probing a hidden-block read (block 5); gdmsetsig needs a gen1a/gdm backdoor. gdm_wakeup_t gw; int wres = gdm_resolve_for_write(gdm, gen1a, wupa, key, keylen, MIFARE_MAGIC_GDM_READBLOCK, 5, true, "hf mf gdmsetsig", diff --git a/doc/commands.json b/doc/commands.json index 425709a23..a01653510 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -6278,7 +6278,7 @@ }, "hf mf gdmsetcfg": { "command": "hf mf gdmsetcfg", - "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt). Note the two groups below are different things: --gdm / --gen1a / --wupa how THIS command talks to the card (access, not stored) --wakestyle / --cuid / ... what gets STORED in the card's config block", + "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt). `access:` flags select how this command talks to the card; `config:` flags change what is stored.", "notes": [ "hf mf gdmsetcfg -d 850000000000000000005A5A00000008", "hf mf gdmsetcfg --cuid on --wakestyle gen1a", From 3599d2f2c0ef60cb39944e7ede76caf98fe3e39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=90=E6=AD=AA?= Date: Mon, 31 Aug 2026 00:46:21 +0800 Subject: [PATCH 5/5] revert: autogenerated commands/vocabulary files --- client/src/pm3line_vocabulary.h | 9 ++++ doc/commands.json | 95 ++++++++++++++++----------------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index e474d0070..8f562b806 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -1071,6 +1071,8 @@ const static vocabulary_t vocabulary[] = { { 0, "script run data_mf_eml2bin.lua" }, { 0, "script run data_mf_eml2html.lua" }, { 0, "script run data_mfu_bin2eml.lua" }, + { 0, "script run example_cmdline.lua" }, + { 0, "script run example_parameters.lua" }, { 0, "script run hf_14a_aztek.lua" }, { 0, "script run hf_14a_i2crevive.lua" }, { 0, "script run hf_14a_protectimus_nfc.lua" }, @@ -1136,6 +1138,13 @@ const static vocabulary_t vocabulary[] = { { 0, "script run ntag_clean.lua" }, { 0, "script run ntag_getsig.lua" }, { 0, "script run ntag_hammertime.lua" }, + { 0, "script run data_tracetest.lua" }, + { 0, "script run hf_read.lua" }, + { 0, "script run lf_t55xx_defaultask.lua" }, + { 0, "script run lf_t55xx_defaultbi.lua" }, + { 0, "script run lf_t55xx_defaultfsk.lua" }, + { 0, "script run lf_t55xx_defaultpsk.lua" }, + { 0, "script run lf_t55xx_writetest.lua" }, { 0, "script run example.cmd" }, { 0, "script run rdv4_init_extflash.cmd" }, { 0, "script run test_psk_clone.cmd" }, diff --git a/doc/commands.json b/doc/commands.json index a01653510..6e66ebb33 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -6188,7 +6188,7 @@ }, "hf mf gdmgetblk": { "command": "hf mf gdmgetblk", - "description": "Read public block(s) from a GDM card. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", + "description": "Read public block(s) from a GDM card", "notes": [ "hf mf gdmgetblk --blk 0", "hf mf gdmgetblk --sec 1 --gdm" @@ -6199,15 +6199,15 @@ "--blk block to read", "--sec sector to read", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgetblk [-h] [--blk ] [--sec ] [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmgetcfg": { "command": "hf mf gdmgetcfg", - "description": "Get configuration data from a GDM card. With no wakeup flag it auto-detects the card's access mode (tries WUPA magic auth, then gen1a, then gdm alt). Use `--gdm`/`--gen1a`/`--wupa` to force one.", + "description": "Get configuration data from a GDM card. By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override.", "notes": [ "hf mf gdmgetcfg", "hf mf gdmgetcfg --gen1a", @@ -6217,15 +6217,15 @@ "options": [ "-h, --help This help", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgetcfg [-h] [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmgethidblk": { "command": "hf mf gdmgethidblk", - "description": "Read hidden block(s) from a GDM card. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt).", + "description": "Read hidden block(s) from a GDM card", "notes": [ "hf mf gdmgethidblk --blk 0", "hf mf gdmgethidblk --sec 1 --gdm" @@ -6236,9 +6236,9 @@ "--blk block to read", "--sec sector to read", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm use gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmgethidblk [-h] [--blk ] [--sec ] [-k ] [--gdm] [--gen1a] [--wupa]" }, @@ -6257,7 +6257,7 @@ }, "hf mf gdmsetblk": { "command": "hf mf gdmsetblk", - "description": "Set public block data on a GDM card With no wakeup flag it auto-detects the card's access mode (gen1a, gdm alt, or WUPA magic auth). `--force` param is used to override warnings like bad ACL writes. if not specified, it will exit if detected", + "description": "Set public block data on a GDM card By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override. `--force` param is used to override warnings like bad ACL writes. if not specified, it will exit if detected", "notes": [ "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f", "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f --gen1a", @@ -6269,20 +6269,19 @@ "--blk public block number", "-d, --data bytes to write, 16 hex bytes", "-k, --key key, 6 hex bytes (only for --wupa mode)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)", + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)", "--force override warnings" ], "usage": "hf mf gdmsetblk [-h] --blk -d [-k ] [--gdm] [--gen1a] [--wupa] [--force]" }, "hf mf gdmsetcfg": { "command": "hf mf gdmsetcfg", - "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back. With no wakeup flag it auto-detects the card's access mode (WUPA magic auth, gen1a, or gdm alt). `access:` flags select how this command talks to the card; `config:` flags change what is stored.", + "description": "Set configuration data on a GDM card Can either write raw 16 bytes (-d) or configure specific flags. If flags are provided, it will read the config, update flags, and write it back.", "notes": [ "hf mf gdmsetcfg -d 850000000000000000005A5A00000008", - "hf mf gdmsetcfg --cuid on --wakestyle gen1a", - "hf mf gdmsetcfg --wakestyle off", + "hf mf gdmsetcfg --cuid on --gen1 on", "hf mf gdmsetcfg --shadow off --sigsec off --wupa -k FFFFFFFFFFFF" ], "offline": false, @@ -6290,22 +6289,22 @@ "-h, --help This help", "-d, --data raw bytes to write, 16 hex bytes", "-k, --key key 6 bytes (only for regular wakeup)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)", - "--cuid config: Gen2/CUID mode", - "--cl2 config: CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>`", - "--shadow config: Shadow mode", - "--magicauth config: Magic auth (what --wupa uses)", - "--statenc config: Static encrypted nonce", - "--sigsec config: Signature sector", - "--wakestyle config: backdoor - gdm (7AFF85), gen1a (7AFF00), or off (8500, seal)" + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)", + "--gen1 Gen1 mode (7A FF)", + "--cuid Gen2/CUID mode", + "--cl2 CL2 mode (7-byte UID) - pair with `hf mf gdmsetuid -u <7-byte>` to set a valid UID", + "--shadow Shadow mode", + "--magicauth Magic auth", + "--statenc Static encrypted nonce", + "--sigsec Signature sector" ], - "usage": "hf mf gdmsetcfg [-h] [-d ] [-k ] [--gdm] [--gen1a] [--wupa] [--cuid ] [--cl2 ] [--shadow ] [--magicauth ] [--statenc ] [--sigsec ] [--wakestyle ]" + "usage": "hf mf gdmsetcfg [-h] [-d ] [-k ] [--gdm] [--gen1a] [--wupa] [--gen1 ] [--cuid ] [--cl2 ] [--shadow ] [--magicauth ] [--statenc ] [--sigsec ]" }, "hf mf gdmsethidblk": { "command": "hf mf gdmsethidblk", - "description": "Write hidden block data on a GDM card. Hidden blocks 0-7 map to the card's hidden sector area. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected. `--force` param is used to override warnings like bad BCC or ACL writes. if not specified, it will exit if detected", + "description": "Write hidden block data on a GDM card. Hidden blocks 0-7 map to the card's hidden sector area. By default uses GDM alt wakeup (20/23). Use `--gen1a` or `--wupa` to override. `--force` param is used to override warnings like bad BCC or ACL writes. if not specified, it will exit if detected", "notes": [ "hf mf gdmsethidblk --blk 0 -d 880494716904EA0C2394510800000000", "hf mf gdmsethidblk --blk 0 -d 880494716904EA0C2394510800000000 --gen1a", @@ -6318,16 +6317,16 @@ "--blk hidden block number (0-7)", "-d, --data bytes to write, 16 hex bytes", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)", + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)", "--force override warnings" ], "usage": "hf mf gdmsethidblk [-h] --blk -d [-k ] [--gdm] [--gen1a] [--wupa] [--force]" }, "hf mf gdmsetsig": { "command": "hf mf gdmsetsig", - "description": "Set MFC EV1 signature on a GDM card. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", + "description": "Set MFC EV1 signature on a GDM card", "notes": [ "hf mf gdmsetsig -s <64 hex chars>" ], @@ -6336,15 +6335,15 @@ "-h, --help This help", "-s, --sig 32-byte signature (64 hex characters)", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)" + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)" ], "usage": "hf mf gdmsetsig [-h] -s [-k ] [--gdm] [--gen1a] [--wupa]" }, "hf mf gdmsetuid": { "command": "hf mf gdmsetuid", - "description": "Set UID on a GDM card. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", + "description": "Set UID on a GDM card", "notes": [ "hf mf gdmsetuid -u 01020304", "hf mf gdmsetuid -u 01020304050607 --gen1a" @@ -6354,16 +6353,16 @@ "-h, --help This help", "-u, --uid UID to set (4 or 7 hex bytes)", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)", + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)", "--f3d use F3 perso mode (writes to hidden block 1 instead of 0)" ], "usage": "hf mf gdmsetuid [-h] -u [-k ] [--gdm] [--gen1a] [--wupa] [--f3d]" }, "hf mf gdmwipe": { "command": "hf mf gdmwipe", - "description": "Wipe a GDM card to factory defaults. With no wakeup flag it auto-detects a backdoor (gen1a or gdm alt); a WUPA-only card is rejected.", + "description": "Wipe a GDM card to factory defaults", "notes": [ "hf mf gdmwipe --gdm" ], @@ -6371,9 +6370,9 @@ "options": [ "-h, --help This help", "-k, --key key 6 bytes (only for --wupa mode)", - "--gdm access: force gdm alt (20/23) magic wakeup", - "--gen1a access: force gen1a (40/43) magic wakeup", - "--wupa access: force regular wakeup (WUPA + magic auth with key)", + "--gdm use gdm alt (20/23) magic wakeup (default)", + "--gen1a use gen1a (40/43) magic wakeup", + "--wupa use regular wakeup (WUPA + magic auth with key)", "-a, --all wipe 4K card (40 sectors) instead of 1K card (16 sectors)" ], "usage": "hf mf gdmwipe [-ha] [-k ] [--gdm] [--gen1a] [--wupa]" @@ -16139,8 +16138,8 @@ } }, "metadata": { - "commands_extracted": 901, + "commands_extracted": 902, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2026-08-22T14:19:35+00:00" + "extracted_on": "2026-08-21T18:43:14+00:00" } }