Merge branch 'master' into mfp_write_checker

Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
Iceman
2026-04-11 14:24:26 +07:00
committed by GitHub
15 changed files with 963 additions and 162 deletions
+2
View File
@@ -362,6 +362,8 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/mifare/gallaghertest.c
${PM3_ROOT}/client/src/relay/relay_posix.c
${PM3_ROOT}/client/src/relay/relay_win32.c
${PM3_ROOT}/client/src/uart/ringbuffer.c
${PM3_ROOT}/client/src/uart/uart_common.c
${PM3_ROOT}/client/src/uart/uart_posix.c
+2
View File
@@ -831,6 +831,8 @@ SRCS = mifare/aiddesfire.c \
pm3line.c \
proxmark3.c \
scandir.c \
relay/relay_posix.c \
relay/relay_win32.c \
uart/ringbuffer.c \
uart/uart_common.c \
uart/uart_posix.c \
+2
View File
@@ -282,6 +282,8 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/mifare/gallaghertest.c
${PM3_ROOT}/client/src/relay/relay_posix.c
${PM3_ROOT}/client/src/relay/relay_win32.c
${PM3_ROOT}/client/src/uart/ringbuffer.c
${PM3_ROOT}/client/src/uart/uart_common.c
${PM3_ROOT}/client/src/uart/uart_posix.c
@@ -0,0 +1,114 @@
[
{
"code": "0003",
"name": "CJRC Standard",
"region": "Japan",
"type": "transit",
"description": "Used by Mutual Use transit cards"
},
{
"code": "0102",
"name": "EZLink",
"region": "Singapore",
"type": "transit",
"description": "Used by legacy EZ-Link transit cards"
},
{
"code": "04C7",
"name": "nanaco",
"region": "Japan",
"type": "payment",
"description": "nanaco e-money system"
},
{
"code": "12FC",
"name": "NDEF Type 3 Tag",
"region": "Global",
"type": "ndef",
"description": "NFC Forum Type 3 Tag system code"
},
{
"code": "8005",
"name": "Shenzhen Tong",
"region": "China",
"type": "transit",
"description": "Used by legacy Shenzen Tong cards"
},
{
"code": "8008",
"name": "Octopus",
"region": "Hong Kong",
"type": "transit",
"description": "Used by Octopus transit cards"
},
{
"code": "852B",
"name": "WAON",
"region": "Japan",
"type": "payment",
"description": "Can be found on some WAON cards"
},
{
"code": "8592",
"name": "PASPY",
"region": "Japan",
"type": "transit",
"description": "PASPY transit card system"
},
{
"code": "86A7",
"name": "Suica",
"region": "Japan",
"type": "transit",
"description": "JR East Suica and related transit cards"
},
{
"code": "88B4",
"name": "FeliCa Lite",
"region": "Global",
"type": "common",
"description": "Default system code used by FeliCa Lite/Lite-S tags"
},
{
"code": "90B7",
"name": "Kartu Multi Trip Commet",
"region": "Indonesia",
"type": "transit",
"description": "Used on Kartu Multi Trip Commet cards"
},
{
"code": "9373",
"name": "Kartu Multi Trip Jelajah",
"region": "Indonesia",
"type": "transit",
"description": "Used on Kartu Multi Trip Jelajah cards"
},
{
"code": "9450",
"name": "HCMC",
"region": "Vietnam",
"type": "transit",
"description": "Used with Ho Chi Minh City Metro transit cards"
},
{
"code": "FE00",
"name": "FeliCa Networks Common Area",
"region": "Japan",
"type": "common",
"description": "Common area for FeliCa Networks services"
},
{
"code": "FE0F",
"name": "Osaifu Keitai Container",
"region": "Japan",
"type": "mobile",
"description": "Container system used by devices with Osaifu-Keitai"
},
{
"code": "FFFF",
"name": "Unfused system",
"region": "Global",
"type": "unfused",
"description": "Default unfused/pre-personalization system"
}
]
+194 -22
View File
@@ -26,6 +26,7 @@
#include "cmdtrace.h"
#include "crc16.h"
#include "util.h"
#include "fileutils.h"
#include "commonutil.h" // ARRAYLEN
#include "ui.h"
#include "iso18.h" // felica_card_select_t struct
@@ -60,6 +61,8 @@
#define FELICA_SEAC_POLL_TIMEOUT_MS 200U
#define FELICA_SEAC_POLL_RETRY_COUNT 5U
#define FELICA_SEAC_POLL_FRAME_LEN 5U
#define FELICA_SYSTEM_CODE_MAX_COUNT 16U
#define FELICA_SYSTEM_LIST_JSON "felica_system_code_list"
#define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001)
#define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010)
@@ -253,6 +256,8 @@ static const char *felica_node_discovery_method_display_name(felica_node_discove
static void felica_print_node_discovery_method_used(felica_node_discovery_method_t method);
static int felica_compare_discovered_nodes(const void *lhs, const void *rhs);
static felica_card_select_t last_known_card;
static json_t *felica_system_list = NULL;
static bool felica_system_list_loaded = false;
static void set_last_known_card(felica_card_select_t card) {
last_known_card = card;
@@ -568,6 +573,161 @@ static void print_platform_information(const uint8_t *platform_information_data,
sprint_hex_inrow(platform_information_data, platform_information_data_len));
}
static json_t *felica_get_system_list(void) {
if (felica_system_list_loaded) {
return felica_system_list;
}
felica_system_list_loaded = true;
char *path = NULL;
if (searchFile(&path, RESOURCES_SUBDIR, FELICA_SYSTEM_LIST_JSON, ".json", true) != PM3_SUCCESS) {
return NULL;
}
json_error_t error;
json_t *root = json_load_file(path, 0, &error);
if (root == NULL) {
PrintAndLogEx(WARNING, "Failed to parse `%s` line %d: %s", path, error.line, error.text);
free(path);
return NULL;
}
if (json_is_array(root) == false) {
PrintAndLogEx(WARNING, "Invalid `%s` format, expected array root", path);
json_decref(root);
free(path);
return NULL;
}
felica_system_list = root;
free(path);
return felica_system_list;
}
static const char *felica_get_json_string(const json_t *obj, const char *key) {
json_t *value = json_object_get(obj, key);
if (json_is_string(value) == false) {
return NULL;
}
const char *str = json_string_value(value);
if (str == NULL || str[0] == '\0') {
return NULL;
}
return str;
}
static const json_t *felica_find_system_annotation(uint16_t system_code) {
json_t *system_list = felica_get_system_list();
if (system_list == NULL) {
return NULL;
}
char code_hex[5] = {0};
snprintf(code_hex, sizeof(code_hex), "%04X", system_code);
size_t index = 0;
json_t *entry = NULL;
json_array_foreach(system_list, index, entry) {
if (json_is_object(entry) == false) {
continue;
}
const char *entry_code = felica_get_json_string(entry, "code");
if (entry_code && strcmp(entry_code, code_hex) == 0) {
return entry;
}
}
return NULL;
}
static void felica_print_system_code_annotation(int level, const uint8_t *system_code_bytes) {
if (system_code_bytes == NULL) {
return;
}
uint16_t system_code = ((uint16_t)system_code_bytes[0] << 8) | system_code_bytes[1];
char code_hex[5] = {0};
snprintf(code_hex, sizeof(code_hex), "%04X", system_code);
const json_t *entry = felica_find_system_annotation(system_code);
if (entry == NULL) {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. UNKNOWN (" _RED_("Report to Iceman!") ")", code_hex);
return;
}
const char *name = felica_get_json_string(entry, "name");
const char *region = felica_get_json_string(entry, "region");
const char *card_type = felica_get_json_string(entry, "type");
if (name == NULL) {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. UNKNOWN (" _RED_("Report to Iceman!") ")", code_hex);
return;
}
if (region && card_type) {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s, %s") ")", code_hex, name, region, card_type);
} else if (region) {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s") ")", code_hex, name, region);
} else if (card_type) {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s") ")", code_hex, name, card_type);
} else {
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s", code_hex, name);
}
}
static int send_request_system_code(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose,
uint32_t timeout_ms, uint32_t retries, bool logging,
felica_syscode_response_t *system_code_response) {
if (system_code_response == NULL) {
return PM3_EINVARG;
}
memset(system_code_response, 0, sizeof(*system_code_response));
PacketResponseNG resp;
if (send_felica_payload_with_retries(flags, datalen, data, verbose,
FELICA_REQSYSCODE_ACK,
timeout_ms, retries,
0, logging, &resp, "request system code") != PM3_SUCCESS) {
return PM3_ERFTRANS;
}
if (resp.length < (sizeof(felica_frame_response_t) + 1 + 2)) {
return PM3_ESOFT;
}
const size_t payload_length = resp.length - 2;
const size_t number_of_systems_offset = sizeof(felica_frame_response_t);
if (payload_length < (number_of_systems_offset + 1)) {
return PM3_ESOFT;
}
uint8_t reported_system_count = resp.data.asBytes[number_of_systems_offset];
const size_t available_system_count = (payload_length - number_of_systems_offset - 1) / 2;
if (reported_system_count > available_system_count) {
return PM3_ESOFT;
}
if (reported_system_count > FELICA_SYSTEM_CODE_MAX_COUNT) {
return PM3_ESOFT;
}
if (reported_system_count == 0) {
memcpy(system_code_response, resp.data.asBytes, sizeof(felica_frame_response_t) + 1);
return PM3_SUCCESS;
}
memcpy(system_code_response, resp.data.asBytes, sizeof(felica_frame_response_t) + 1);
memcpy(system_code_response->system_code_list,
resp.data.asBytes + number_of_systems_offset + 1,
(size_t)reported_system_count * 2U);
return PM3_SUCCESS;
}
/**
* Wait for response from pm3 or timeout.
* Checks if receveid bytes have a valid CRC.
@@ -1047,7 +1207,7 @@ static int info_felica(bool verbose) {
memcpy(&card, (felica_card_select_t *)resp.data.asBytes, sizeof(felica_card_select_t));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(INFO, "IDm............ " _YELLOW_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
PrintAndLogEx(INFO, "Primary IDm.... " _YELLOW_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
PrintAndLogEx(INFO, " Code......... " _GREEN_("%s"), sprint_hex_inrow(card.code, sizeof(card.code)));
PrintAndLogEx(INFO, " NFCID2....... " _GREEN_("%s"), sprint_hex_inrow(card.uid, sizeof(card.uid)));
PrintAndLogEx(INFO, "PMM............ " _YELLOW_("%s"), sprint_hex_inrow(card.PMm, sizeof(card.PMm)));
@@ -1160,6 +1320,24 @@ static int info_felica(bool verbose) {
}
}
felica_request_system_code_request_t request_system_code_request;
memset(&request_system_code_request, 0, sizeof(request_system_code_request));
request_system_code_request.length[0] = sizeof(request_system_code_request);
request_system_code_request.command_code[0] = FELICA_REQSYSCODE_REQ;
memcpy(request_system_code_request.IDm, card.IDm, sizeof(request_system_code_request.IDm));
felica_syscode_response_t system_code_response;
if (send_request_system_code(optional_flags,
sizeof(request_system_code_request), (uint8_t *)&request_system_code_request,
false, FELICA_OPTIONAL_CMD_TIMEOUT_MS, FELICA_OPTIONAL_CMD_RETRIES, false,
&system_code_response) == PM3_SUCCESS &&
system_code_response.number_of_systems[0] > 0) {
PrintAndLogEx(INFO, "System codes.... " _GREEN_("%u"), system_code_response.number_of_systems[0]);
for (size_t i = 0; i < system_code_response.number_of_systems[0]; i++) {
felica_print_system_code_annotation(INFO, system_code_response.system_code_list + (i * 2));
}
}
DropField();
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
@@ -3391,38 +3569,32 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
CLIParserFree(ctx);
uint8_t data[PM3_CMD_DATA_SIZE];
memset(data, 0, sizeof(data));
data[0] = 0x0A; // Static length
data[1] = 0x0C; // Command ID
felica_request_system_code_request_t request_system_code_request;
memset(&request_system_code_request, 0, sizeof(request_system_code_request));
request_system_code_request.length[0] = sizeof(request_system_code_request);
request_system_code_request.command_code[0] = FELICA_REQSYSCODE_REQ;
uint16_t datalen = 10; // Length (1), Command ID (1), IDm (8)
res = felica_ensure_target_present(idm, (size_t)ilen, FELICA_IDM_RESOLVE_STANDALONE, data + 2);
res = felica_ensure_target_present(idm, (size_t)ilen, FELICA_IDM_RESOLVE_STANDALONE, request_system_code_request.IDm);
if (res != PM3_SUCCESS) {
return res;
}
uint8_t flags = (FELICA_APPEND_CRC | FELICA_RAW);
clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp;
if (waitCmdFelica(false, &resp, true) == false) {
felica_syscode_response_t system_code_response;
if (send_request_system_code(flags,
sizeof(request_system_code_request), (uint8_t *)&request_system_code_request,
false,
FELICA_DEFAULT_TIMEOUT_MS, FELICA_DEFAULT_RETRY_COUNT, true,
&system_code_response) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Got no response from card");
return PM3_ERFTRANS;
}
felica_syscode_response_t rq_syscode_response;
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t));
if (system_code_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(INFO, "Systems........ " _GREEN_("%u"), system_code_response.number_of_systems[0]);
if (rq_syscode_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "Request Response");
PrintAndLogEx(SUCCESS, "IDm... %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm)));
PrintAndLogEx(SUCCESS, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems)));
PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0.");
for (int i = 0; i < rq_syscode_response.number_of_systems[0]; i++) {
PrintAndLogEx(SUCCESS, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, 2));
for (size_t i = 0; i < system_code_response.number_of_systems[0]; i++) {
felica_print_system_code_annotation(INFO, system_code_response.system_code_list + (i * 2));
}
}
+73 -117
View File
@@ -24,17 +24,7 @@
#include <math.h>
#include <unistd.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include "relay/relay.h"
#include "cmdparser.h" // command_t
#include "comms.h"
@@ -1722,33 +1712,9 @@ static int check_autocorrelate(const char *prefix, int clock) {
static int lf_relay_tag(uint64_t samples, uint16_t port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
PrintAndLogEx(ERR, "Failed to create socket");
return PM3_EFAILED;
}
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr.s_addr = INADDR_ANY };
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u"), port);
close(sock);
return PM3_EFAILED;
}
if (listen(sock, 1) < 0) {
PrintAndLogEx(ERR, "Failed to listen on socket");
close(sock);
return PM3_EFAILED;
}
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
int client = accept(sock, NULL, NULL);
if (client < 0) {
PrintAndLogEx(ERR, "Failed to accept connection");
close(sock);
relay_socket_t listen_sock = RELAY_SOCKET_INVALID;
relay_socket_t client = relay_listen_accept(port, &listen_sock);
if (client == RELAY_SOCKET_INVALID) {
return PM3_EFAILED;
}
@@ -1763,49 +1729,32 @@ static int lf_relay_tag(uint64_t samples, uint16_t port) {
lf_read_internal(false, false, samples);
if (g_GraphTraceLen > 1000 && !getSignalProperties()->isnoise) {
if ((g_GraphTraceLen > 1000) && (getSignalProperties()->isnoise == false)) {
PrintAndLogEx(INFO, "Tag detected! Sending %zu samples to Client...", g_GraphTraceLen);
uint32_t len = (uint32_t)g_GraphTraceLen;
if (send(client, &len, sizeof(len), 0) < 0) {
if (relay_send_all(client, &len, sizeof(len)) != 0) {
break;
}
if (send(client, g_GraphBuffer, len * sizeof(int32_t), 0) < 0) {
if (relay_send_all(client, g_GraphBuffer, len * sizeof(int32_t)) != 0) {
break;
}
msleep(500);
}
}
close(client);
close(sock);
relay_close(client);
relay_close(listen_sock);
return PM3_SUCCESS;
}
static int lf_relay_rdr(const char *ip, uint16_t port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
PrintAndLogEx(ERR, "Failed to create socket");
return PM3_EFAILED;
}
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
close(sock);
return PM3_EFAILED;
}
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
PrintAndLogEx(ERR, "Connection error to %s:%u", ip, port);
close(sock);
relay_socket_t sock = relay_connect(ip, port);
if (sock == RELAY_SOCKET_INVALID) {
return PM3_EFAILED;
}
@@ -1814,9 +1763,9 @@ static int lf_relay_rdr(const char *ip, uint16_t port) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
PrintAndLogEx(NORMAL, "");
int n = 0;
do {
bool running = true;
while (running) {
if (kbd_enter_pressed()) {
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
PrintAndLogEx(DEBUG, "\naborted via keyboard!");
@@ -1825,67 +1774,74 @@ static int lf_relay_rdr(const char *ip, uint16_t port) {
}
uint32_t incoming_len = 0;
n = recv(sock, &incoming_len, sizeof(incoming_len), MSG_WAITALL);
if (n > 0 && incoming_len > 0) {
if (incoming_len > MAX_GRAPH_TRACE_LEN) {
PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, MAX_GRAPH_TRACE_LEN);
break;
}
PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len);
ssize_t rx = recv(sock, g_GraphBuffer, incoming_len * sizeof(int32_t), MSG_WAITALL);
if (rx != (ssize_t)(incoming_len * sizeof(int32_t))) {
PrintAndLogEx(ERR, "Short read: expected %u bytes, got %zd", incoming_len * (uint32_t)sizeof(int32_t), rx);
break;
}
// if previous simulation running, we need to break it.
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
msleep(300);
g_GraphTraceLen = incoming_len;
lf_chk_bitstream();
lfsim_upload_gb();
struct {
uint16_t len;
uint16_t gap;
} PACKED payload;
payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen;
payload.gap = 0;
clearCommandBuffer();
SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PrintAndLogEx(SUCCESS, "Simulation active.");
int n = relay_recv_all(sock, &incoming_len, sizeof(incoming_len));
if (n < 0) {
break;
}
} while (n > 0);
if (incoming_len == 0) {
continue;
}
close(sock);
if (incoming_len > MAX_GRAPH_TRACE_LEN) {
PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, (uint32_t)MAX_GRAPH_TRACE_LEN);
break;
}
PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len);
int rx = relay_recv_all(sock, g_GraphBuffer, incoming_len * sizeof(int32_t));
if (rx < 0) {
PrintAndLogEx(ERR, "Short read receiving sample data");
break;
}
// if previous simulation running, we need to break it.
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
msleep(300);
g_GraphTraceLen = incoming_len;
lf_chk_bitstream();
lfsim_upload_gb();
struct {
uint16_t len;
uint16_t gap;
} PACKED payload;
payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen;
payload.gap = 0;
clearCommandBuffer();
SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PrintAndLogEx(SUCCESS, "Simulation active.");
}
relay_close(sock);
return PM3_SUCCESS;
}
int CmdLFRelay(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf relay",
"Relay LF signal between two Proxmark3 devices over TCP.\n"
"By default it uses PORT 8000.\n"
"One device acts as a Tag Proxy, the other as a Reader Client.",
"lf relay --tag -s 7000\n"
"lf relay --rdr --ip 192.168.1.141"
);
"Relay LF signal between two Proxmark3 devices over TCP.\n"
"By default it uses PORT 8000 and uses 40000 samples from Graphbuffer\n"
" --rdr : Reading device, act as IP client and reads LF tag and sends data\n"
" --tag : Simulation device, act as IP server and simulates relayed data\n",
_WHITE_("Device A, reading LF tag, client") "\n"
"lf relay --rdr --ip 192.168.1.141 -> Client, connect to IP 192.168.1.141:8000\n"
"lf relay --rdr --ip 192.168.1.141 -p 18111 -> Client, connect to IP 192.168.1.141:18111 \n\n"
_WHITE_("Device B, simulate LF tag, server") "\n"
"lf relay --tag -p 8111 -> Server listening port 8111, recv 40000 samples\n"
"lf relay --tag -s 10000 -> Server listening port 8000, recv 10000 samples\n"
);
void *argtable[] = {
arg_param_begin,
arg_lit0(NULL, "tag", "Act as Tag Proxy (Server)"),
arg_lit0(NULL, "rdr", "Act as Reader Client (Connects to Proxy)"),
arg_str0("i", "ip", "<i>", "Target IP address for Reader mode"),
arg_u64_0("s", "samples", "<dec>", "Number of samples to collect (default 40000)"),
arg_lit0(NULL, "tag", "Simulation device, act as Server"),
arg_lit0(NULL, "rdr", "Sniffing device, act as client"),
arg_str0("i", "ip", "<ipaddr>", "Target IPv4 address to send data to. Used with `--rdr`"),
arg_u64_0("s", "samples", "<dec>", "Number of samples to collect (def: 40000)"),
arg_u64_0("p", "port", "<dec>", "Port number (def: 8000)"),
arg_param_end
};
+4 -2
View File
@@ -293,6 +293,7 @@ const static vocabulary_t vocabulary[] = {
{ 0, "hf gst info" },
{ 0, "hf gst read" },
{ 1, "hf secc help" },
{ 0, "hf secc info" },
{ 0, "hf secc sim" },
{ 0, "hf secc sniff" },
{ 1, "hf iclass help" },
@@ -435,6 +436,7 @@ const static vocabulary_t vocabulary[] = {
{ 0, "hf mf encodehid" },
{ 1, "hf mfp help" },
{ 1, "hf mfp list" },
{ 1, "hf mfp acl" },
{ 0, "hf mfp auth" },
{ 0, "hf mfp chk" },
{ 0, "hf mfp dump" },
@@ -620,6 +622,7 @@ const static vocabulary_t vocabulary[] = {
{ 0, "lf config" },
{ 0, "lf cmdread" },
{ 0, "lf read" },
{ 0, "lf relay" },
{ 1, "lf search" },
{ 0, "lf sim" },
{ 0, "lf simask" },
@@ -1024,10 +1027,10 @@ const static vocabulary_t vocabulary[] = {
{ 0, "script run hf_ntag_bruteforce.lua" },
{ 0, "script run hf_ntag_dt.lua" },
{ 0, "script run init_rdv4.lua" },
{ 0, "script run kybercrystals.lua" },
{ 0, "script run lf_awid_bulkclone.lua" },
{ 0, "script run lf_electra.lua" },
{ 0, "script run lf_em4100_bulk.lua" },
{ 0, "script run lf_em4x05_kybercrystals.lua" },
{ 0, "script run lf_em_tearoff.lua" },
{ 0, "script run lf_em_tearoff_protect.lua" },
{ 0, "script run lf_hid_bulkclone.lua" },
@@ -1046,7 +1049,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 paxton_clone.lua" },
{ 0, "script run data_tracetest.lua" },
{ 0, "script run hf_read.lua" },
{ 0, "script run lf_t55xx_defaultask.lua" },
+62
View File
@@ -0,0 +1,62 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// TCP relay socket abstraction layer
//-----------------------------------------------------------------------------
#ifndef RELAY_H__
#define RELAY_H__
#include "common.h"
#ifdef _WIN32
#include <winsock2.h>
typedef SOCKET relay_socket_t;
#define RELAY_SOCKET_INVALID INVALID_SOCKET
#else
typedef int relay_socket_t;
#define RELAY_SOCKET_INVALID (-1)
#endif
// Initialize relay subsystem (call once at startup).
// On Win32 this calls WSAStartup; on POSIX it is a no-op.
int relay_init(void);
// Tear down relay subsystem (call once at shutdown).
// On Win32 this calls WSACleanup; on POSIX it is a no-op.
void relay_cleanup(void);
// Create a TCP server socket bound to INADDR_ANY:<port>, listen, and
// block until one client connects. Returns the *client* fd/SOCKET.
// On error, returns RELAY_SOCKET_INVALID. Caller owns both sockets;
// the listening socket is written to *listen_sock so it can be closed.
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock);
// Connect to a TCP server at ip:port.
// Returns the connected socket or RELAY_SOCKET_INVALID on error.
relay_socket_t relay_connect(const char *ip, uint16_t port);
// Send exactly `len` bytes from `buf`.
// Returns 0 on success, -1 on error.
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len);
// Receive exactly `len` bytes into `buf`.
// Returns number of bytes received, or -1 on error / disconnect.
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len);
// Close a relay socket.
void relay_close(relay_socket_t sock);
#endif // RELAY_H__
+148
View File
@@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// TCP relay socket abstraction — POSIX implementation
//-----------------------------------------------------------------------------
#ifndef _WIN32
#include "relay.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "ui.h"
int relay_init(void) {
return PM3_SUCCESS;
}
void relay_cleanup(void) {
}
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno));
return RELAY_SOCKET_INVALID;
}
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = INADDR_ANY
};
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (%s)", port, strerror(errno));
close(sock);
return RELAY_SOCKET_INVALID;
}
if (listen(sock, 1) < 0) {
PrintAndLogEx(ERR, "Failed to listen on socket (%s)", strerror(errno));
close(sock);
return RELAY_SOCKET_INVALID;
}
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
int client = accept(sock, NULL, NULL);
if (client < 0) {
PrintAndLogEx(ERR, "Failed to accept connection (%s)", strerror(errno));
close(sock);
return RELAY_SOCKET_INVALID;
}
if (listen_sock != NULL) {
*listen_sock = sock;
}
return client;
}
relay_socket_t relay_connect(const char *ip, uint16_t port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno));
return RELAY_SOCKET_INVALID;
}
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
close(sock);
return RELAY_SOCKET_INVALID;
}
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
PrintAndLogEx(ERR, "Connection error to %s:%u (%s)", ip, port, strerror(errno));
close(sock);
return RELAY_SOCKET_INVALID;
}
return sock;
}
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) {
const uint8_t *p = (const uint8_t *)buf;
uint32_t remaining = len;
while (remaining > 0) {
ssize_t n = send(sock, p, remaining, 0);
if (n <= 0) {
return -1;
}
p += n;
remaining -= (uint32_t)n;
}
return 0;
}
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) {
uint8_t *p = (uint8_t *)buf;
uint32_t remaining = len;
while (remaining > 0) {
ssize_t n = recv(sock, p, remaining, 0);
if (n <= 0) {
return -1;
}
p += n;
remaining -= (uint32_t)n;
}
return (int)len;
}
void relay_close(relay_socket_t sock) {
if (sock != RELAY_SOCKET_INVALID) {
close(sock);
}
}
#endif // !_WIN32
+175
View File
@@ -0,0 +1,175 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// TCP relay socket abstraction — Win32 implementation
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include "relay.h"
#include <stdio.h>
#include <string.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include "ui.h"
static bool g_wsa_initialized = false;
int relay_init(void) {
if (g_wsa_initialized) {
return PM3_SUCCESS;
}
WSADATA wsa;
int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
if (ret != 0) {
PrintAndLogEx(ERR, "WSAStartup failed with error %d", ret);
return PM3_EFAILED;
}
g_wsa_initialized = true;
return PM3_SUCCESS;
}
void relay_cleanup(void) {
if (g_wsa_initialized) {
WSACleanup();
g_wsa_initialized = false;
}
}
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) {
if (relay_init() != PM3_SUCCESS) {
return RELAY_SOCKET_INVALID;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError());
return RELAY_SOCKET_INVALID;
}
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (WSA %d)", port, WSAGetLastError());
closesocket(sock);
return RELAY_SOCKET_INVALID;
}
if (listen(sock, 1) == SOCKET_ERROR) {
PrintAndLogEx(ERR, "Failed to listen on socket (WSA %d)", WSAGetLastError());
closesocket(sock);
return RELAY_SOCKET_INVALID;
}
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
SOCKET client = accept(sock, NULL, NULL);
if (client == INVALID_SOCKET) {
PrintAndLogEx(ERR, "Failed to accept connection (WSA %d)", WSAGetLastError());
closesocket(sock);
return RELAY_SOCKET_INVALID;
}
if (listen_sock != NULL) {
*listen_sock = sock;
}
return client;
}
relay_socket_t relay_connect(const char *ip, uint16_t port) {
if (relay_init() != PM3_SUCCESS) {
return RELAY_SOCKET_INVALID;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError());
return RELAY_SOCKET_INVALID;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
closesocket(sock);
return RELAY_SOCKET_INVALID;
}
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
PrintAndLogEx(ERR, "Connection error to %s:%u (WSA %d)", ip, port, WSAGetLastError());
closesocket(sock);
return RELAY_SOCKET_INVALID;
}
return sock;
}
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) {
const char *p = (const char *)buf;
uint32_t remaining = len;
while (remaining > 0) {
int n = send(sock, p, (int)remaining, 0);
if (n == SOCKET_ERROR || n <= 0) {
return -1;
}
p += n;
remaining -= (uint32_t)n;
}
return 0;
}
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) {
char *p = (char *)buf;
uint32_t remaining = len;
while (remaining > 0) {
int n = recv(sock, p, (int)remaining, 0);
if (n == SOCKET_ERROR || n <= 0) {
return -1;
}
p += n;
remaining -= (uint32_t)n;
}
return (int)len;
}
void relay_close(relay_socket_t sock) {
if (sock != INVALID_SOCKET) {
closesocket(sock);
}
}
#endif // _WIN32