1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3 // Copyright (C) 2011 Gerhard de Koning Gans
4 // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
6 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
7 // at your option, any later version. See the LICENSE.txt file for the text of
9 //-----------------------------------------------------------------------------
10 // High frequency iClass commands
11 //-----------------------------------------------------------------------------
17 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
19 #include "proxmark3.h"
21 #include "cmdparser.h"
22 #include "cmdhficlass.h"
26 #include "loclass/des.h"
27 #include "loclass/cipherutils.h"
28 #include "loclass/cipher.h"
29 #include "loclass/ikeys.h"
30 #include "loclass/elite_crack.h"
31 #include "loclass/fileutils.h"
32 #include "protocols.h"
35 static int CmdHelp(const char *Cmd
);
37 int xorbits_8(uint8_t val
)
39 uint8_t res
= val
^ (val
>> 1); //1st pass
40 res
= res
^ (res
>> 1); // 2nd pass
41 res
= res
^ (res
>> 2); // 3rd pass
42 res
= res
^ (res
>> 4); // 4th pass
46 int CmdHFiClassList(const char *Cmd
)
48 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
52 int CmdHFiClassSnoop(const char *Cmd
)
54 UsbCommand c
= {CMD_SNOOP_ICLASS
};
58 int usage_hf_iclass_sim()
60 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
61 PrintAndLog(" options");
62 PrintAndLog(" 0 <CSN> simulate the given CSN");
63 PrintAndLog(" 1 simulate default CSN");
64 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
65 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
66 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
67 PrintAndLog(" example: hf iclass sim 2");
68 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
69 PrintAndLog(" hf iclass sim 3");
74 int CmdHFiClassSim(const char *Cmd
)
77 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
80 return usage_hf_iclass_sim();
82 simType
= param_get8ex(Cmd
, 0, 0, 10);
86 if (param_gethex(Cmd
, 1, CSN
, 16)) {
87 PrintAndLog("A CSN should consist of 16 HEX symbols");
88 return usage_hf_iclass_sim();
91 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
95 PrintAndLog("Undefined simptype %d", simType
);
96 return usage_hf_iclass_sim();
99 uint8_t numberOfCSNs
=0;
102 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
103 UsbCommand resp
= {0};
105 uint8_t csns
[8*NUM_CSNS
] = {
106 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
107 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
108 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
109 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
110 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
111 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
112 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
113 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
114 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
115 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
116 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
117 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
118 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
119 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
120 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
122 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
125 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
126 PrintAndLog("Command timed out");
130 uint8_t num_mac_responses
= resp
.arg
[1];
131 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
,NUM_CSNS
);
133 size_t datalen
= NUM_CSNS
*24;
135 * Now, time to dump to file. We'll use this format:
136 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
137 * So, it should wind up as
140 * The returndata from the pm3 is on the following format
141 * <4 byte NR><4 byte MAC>
142 * CC are all zeroes, CSN is the same as was sent in
144 void* dump
= malloc(datalen
);
145 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
147 for(i
= 0 ; i
< NUM_CSNS
; i
++)
149 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
150 //8 zero bytes here...
151 //Then comes NR_MAC (eight bytes from the response)
152 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
155 /** Now, save to dumpfile **/
156 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
160 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
161 memcpy(c
.d
.asBytes
, CSN
, 8);
168 int CmdHFiClassReader(const char *Cmd
)
170 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
|
171 FLAG_ICLASS_READER_CONF
|FLAG_ICLASS_READER_AA
}};
175 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
176 uint8_t readStatus
= resp
.arg
[0] & 0xff;
177 uint8_t * data
= resp
.d
.asBytes
;
179 PrintAndLog("Readstatus:%02x", readStatus
);
180 if( readStatus
== 0){
182 PrintAndLog("Quitting...");
185 if( readStatus
& FLAG_ICLASS_READER_CSN
) PrintAndLog("CSN: %s",sprint_hex(data
,8));
186 if( readStatus
& FLAG_ICLASS_READER_CC
) PrintAndLog("CC: %s",sprint_hex(data
+16,8));
187 if( readStatus
& FLAG_ICLASS_READER_CONF
){
188 printIclassDumpInfo(data
);
191 PrintAndLog("Command execute timeout");
198 int CmdHFiClassReader_Replay(const char *Cmd
)
200 uint8_t readerType
= 0;
201 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
204 PrintAndLog("Usage: hf iclass replay <MAC>");
205 PrintAndLog(" sample: hf iclass replay 00112233");
209 if (param_gethex(Cmd
, 0, MAC
, 8)) {
210 PrintAndLog("MAC must include 8 HEX symbols");
214 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
215 memcpy(c
.d
.asBytes
, MAC
, 4);
221 int CmdHFiClassReader_Dump(const char *Cmd
)
223 uint8_t readerType
= 0;
224 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
225 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
226 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
227 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
228 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
229 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
230 uint8_t keytable
[128] = {0};
236 PrintAndLog("Usage: hf iclass dump <Key> [e]");
237 PrintAndLog(" Key - A 16 byte master key");
238 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
239 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
240 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
241 PrintAndLog(" sample: hf iclass dump 0011223344556677");
247 if (param_gethex(Cmd
, 0, KEY
, 16))
249 PrintAndLog("KEY must include 16 HEX symbols");
253 if (param_getchar(Cmd
, 1) == 'e')
255 PrintAndLog("Elite switch on");
259 hash2(KEY
, keytable
);
260 printarr_human_readable("keytable", keytable
, 128);
265 uint8_t key_sel
[8] = {0};
266 uint8_t key_sel_p
[8] = { 0 };
268 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
269 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
| FLAG_ICLASS_READER_CC
;
274 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
276 PrintAndLog("Command execute timeout");
280 uint8_t isOK
= resp
.arg
[0] & 0xff;
281 uint8_t * data
= resp
.d
.asBytes
;
284 memcpy(CCNR
,data
+16,8);
286 PrintAndLog("isOk:%02x", isOK
);
290 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
293 PrintAndLog("Failed to obtain CC! Aborting");
300 //Get the key index (hash1)
301 uint8_t key_index
[8] = {0};
303 hash1(CSN
, key_index
);
304 printvar("hash1", key_index
,8);
305 for(i
= 0; i
< 8 ; i
++)
306 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
307 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
308 printvar("k_sel", key_sel
,8);
309 //Permute from iclass format to standard format
310 permutekey_rev(key_sel
,key_sel_p
);
311 used_key
= key_sel_p
;
316 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
317 printvar("Used key",used_key
,8);
318 diversifyKey(CSN
,used_key
, div_key
);
319 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
320 printvar("Div key", div_key
, 8);
321 printvar("CC_NR:",CCNR
,12);
322 doMAC(CCNR
,div_key
, MAC
);
323 printvar("MAC", MAC
, 4);
325 uint8_t iclass_data
[32000] = {0};
326 uint32_t iclass_datalen
= 0;
327 uint32_t iclass_blocksFailed
= 0;//Set to 1 if dump was incomplete
329 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
330 memcpy(d
.d
.asBytes
, MAC
, 4);
331 clearCommandBuffer();
333 PrintAndLog("Waiting for device to dump data. Press button on device and key on keyboard to abort...");
338 printf("\naborted via keyboard!\n");
341 if(WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
343 uint32_t dataLength
= resp
.arg
[0];
344 iclass_blocksFailed
|= resp
.arg
[1];
347 PrintAndLog("Got %d bytes data (total so far %d)" ,dataLength
,iclass_datalen
);
348 memcpy(iclass_data
, resp
.d
.asBytes
,dataLength
);
349 iclass_datalen
+= dataLength
;
351 {//Last transfer, datalength 0 means the dump is finished
352 PrintAndLog("Dumped %d bytes of data from tag. ", iclass_datalen
);
353 if(iclass_blocksFailed
)
355 PrintAndLog("OBS! Some blocks failed to be dumped correctly!");
357 if(iclass_datalen
> 0)
359 char filename
[100] = {0};
360 //create a preferred filename
361 snprintf(filename
, 100,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
362 CSN
[0],CSN
[1],CSN
[2],CSN
[3],
363 CSN
[4],CSN
[5],CSN
[6],CSN
[7]);
364 //Place the div_key in block 3
365 memcpy(iclass_data
+(3*8), div_key
, 8);
366 saveFile(filename
,"bin",iclass_data
, iclass_datalen
);
368 //Aaaand we're finished
378 int hf_iclass_eload_usage()
380 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
381 PrintAndLog("Usage: hf iclass eload f <filename>");
383 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
388 int iclassEmlSetMem(uint8_t *data
, int blockNum
, int blocksCount
) {
389 UsbCommand c
= {CMD_MIFARE_EML_MEMSET
, {blockNum
, blocksCount
, 0}};
390 memcpy(c
.d
.asBytes
, data
, blocksCount
* 16);
394 int CmdHFiClassELoad(const char *Cmd
)
397 char opt
= param_getchar(Cmd
, 0);
398 if (strlen(Cmd
)<1 || opt
== 'h')
399 return hf_iclass_eload_usage();
401 //File handling and reading
403 char filename
[FILE_PATH_SIZE
];
404 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
) > 0)
406 f
= fopen(filename
, "rb");
408 return hf_iclass_eload_usage();
412 PrintAndLog("Failed to read from file '%s'", filename
);
416 fseek(f
, 0, SEEK_END
);
417 long fsize
= ftell(f
);
418 fseek(f
, 0, SEEK_SET
);
420 uint8_t *dump
= malloc(fsize
);
423 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
426 printIclassDumpInfo(dump
);
429 if (bytes_read
< fsize
)
431 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
436 uint32_t bytes_sent
= 0;
437 uint32_t bytes_remaining
= bytes_read
;
439 while(bytes_remaining
> 0){
440 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
441 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
442 memcpy(c
.d
.asBytes
, dump
, bytes_in_packet
);
444 bytes_remaining
-= bytes_in_packet
;
445 bytes_sent
+= bytes_in_packet
;
448 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
452 int usage_hf_iclass_decrypt()
454 PrintAndLog("Usage: hf iclass decrypt f <tagdump> o ");
456 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
457 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
459 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
461 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
462 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
463 PrintAndLog("which is defined by the configuration block.");
467 int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
)
469 FILE *f
= fopen(filename
, "rb");
471 PrintAndLog("Failed to read from file '%s'", filename
);
474 fseek(f
, 0, SEEK_END
);
475 long fsize
= ftell(f
);
476 fseek(f
, 0, SEEK_SET
);
477 size_t bytes_read
= fread(buffer
, 1, len
, f
);
481 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
484 if(bytes_read
!= len
)
486 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
492 int CmdHFiClassDecrypt(const char *Cmd
)
494 uint8_t key
[16] = { 0 };
495 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
497 usage_hf_iclass_decrypt();
500 PrintAndLog("Decryption file found... ");
501 char opt
= param_getchar(Cmd
, 0);
502 if (strlen(Cmd
)<1 || opt
== 'h')
503 return usage_hf_iclass_decrypt();
505 //Open the tagdump-file
507 char filename
[FILE_PATH_SIZE
];
508 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
) > 0)
510 f
= fopen(filename
, "rb");
512 return usage_hf_iclass_decrypt();
515 fseek(f
, 0, SEEK_END
);
516 long fsize
= ftell(f
);
517 fseek(f
, 0, SEEK_SET
);
518 uint8_t enc_dump
[8] = {0};
519 uint8_t *decrypted
= malloc(fsize
);
520 des3_context ctx
= { DES_DECRYPT
,{ 0 } };
521 des3_set2key_dec( &ctx
, key
);
522 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
524 //Use the first block (CSN) for filename
525 char outfilename
[FILE_PATH_SIZE
] = { 0 };
526 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
527 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
528 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
531 while(bytes_read
== 8)
535 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
537 des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
539 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
540 bytes_read
= fread(enc_dump
, 1, 8, f
);
545 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
550 int CmdHFiClass_iso14443A_write(const char *Cmd
)
552 uint8_t readerType
= 0;
553 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
554 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
555 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
556 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
557 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
560 uint8_t bldata
[8]={0};
564 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
565 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
569 if (param_gethex(Cmd
, 0, KEY
, 16))
571 PrintAndLog("KEY must include 16 HEX symbols");
575 blockNo
= param_get8(Cmd
, 1);
578 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
581 if (param_gethex(Cmd
, 2, bldata
, 8))
583 PrintAndLog("Block data must include 8 HEX symbols");
587 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
591 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
592 uint8_t isOK
= resp
.arg
[0] & 0xff;
593 uint8_t * data
= resp
.d
.asBytes
;
596 memcpy(CCNR
,data
+8,8);
597 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
598 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
599 PrintAndLog("isOk:%02x", isOK
);
601 PrintAndLog("Command execute timeout");
604 diversifyKey(CSN
,KEY
, div_key
);
606 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
607 doMAC(CCNR
, div_key
, MAC
);
609 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
610 memcpy(c2
.d
.asBytes
, bldata
, 8);
611 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
614 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
615 uint8_t isOK
= resp
.arg
[0] & 0xff;
616 uint8_t * data
= resp
.d
.asBytes
;
619 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
621 PrintAndLog("isOk:%02x", isOK
);
623 PrintAndLog("Command execute timeout");
627 int CmdHFiClass_loclass(const char *Cmd
)
629 char opt
= param_getchar(Cmd
, 0);
631 if (strlen(Cmd
)<1 || opt
== 'h') {
632 PrintAndLog("Usage: hf iclass loclass [options]");
633 PrintAndLog("Options:");
634 PrintAndLog("h Show this help");
635 PrintAndLog("t Perform self-test");
636 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
637 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
638 PrintAndLog(" malicious CSNs, and their protocol responses");
639 PrintAndLog(" The the binary format of the file is expected to be as follows: ");
640 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
641 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
642 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
643 PrintAndLog(" ... totalling N*24 bytes");
646 char fileName
[255] = {0};
649 if(param_getstr(Cmd
, 1, fileName
) > 0)
651 return bruteforceFileNoKeys(fileName
);
654 PrintAndLog("You must specify a filename");
659 int errors
= testCipherUtils();
661 errors
+= doKeyTests(0);
662 errors
+= testElite();
665 prnlog("OBS! There were errors!!!");
673 static command_t CommandTable
[] =
675 {"help", CmdHelp
, 1, "This help"},
676 {"list", CmdHFiClassList
, 0, "[Deprecated] List iClass history"},
677 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
678 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
679 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
680 {"replay",CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
681 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
682 // {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
683 {"loclass", CmdHFiClass_loclass
, 1, "Use loclass to perform bruteforce of reader attack dump"},
684 {"eload", CmdHFiClassELoad
, 0, "[experimental] Load data into iclass emulator memory"},
685 {"decrypt", CmdHFiClassDecrypt
, 1, "Decrypt tagdump" },
686 {NULL
, NULL
, 0, NULL
}
689 int CmdHFiClass(const char *Cmd
)
691 CmdsParse(CommandTable
, Cmd
);
695 int CmdHelp(const char *Cmd
)
697 CmdsHelp(CommandTable
);