mirror of
https://github.com/RfidResearchGroup/RFIDtools.git
synced 2026-05-12 11:19:59 -07:00
Some unused resource clean up.
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
|
||||
# Cmake gen
|
||||
.cxx/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following line if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
@@ -1,45 +0,0 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
|
||||
}
|
||||
//abiFilters "armeabi"
|
||||
/*abiFilters "arm64-v8a"*/
|
||||
/*abiFilters "x86_64"*/
|
||||
/*abiFilters "arm64-v8a"
|
||||
abiFilters "mips"
|
||||
abiFilters "mips64"
|
||||
abiFilters "x86"
|
||||
abiFilters "x86_64"*/
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.10.2'
|
||||
path 'src/main/cpp/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api project(':console')
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
}
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,2 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cn.rrg.mfkey" />
|
||||
@@ -1,38 +0,0 @@
|
||||
#需要的最cmake版本
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
#添加动态库定义
|
||||
add_library(mfkey32 SHARED
|
||||
mfkey32.c
|
||||
tools.c
|
||||
parity.c
|
||||
mfkey.c
|
||||
util_posix.c
|
||||
crypto1.c
|
||||
crapto1.c
|
||||
bucketsort.c
|
||||
)
|
||||
|
||||
#添加头文件配置
|
||||
target_include_directories(mfkey32 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/)
|
||||
|
||||
#添加动态库链接!
|
||||
target_link_libraries(mfkey32 android log)
|
||||
|
||||
#添加动态库定义
|
||||
add_library(mfkey64 SHARED
|
||||
mfkey64.c
|
||||
tools.c
|
||||
parity.c
|
||||
mfkey.c
|
||||
util_posix.c
|
||||
crypto1.c
|
||||
crapto1.c
|
||||
bucketsort.c
|
||||
)
|
||||
|
||||
#添加头文件配置
|
||||
target_include_directories(mfkey64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/)
|
||||
|
||||
#添加动态库链接!
|
||||
target_link_libraries(mfkey64 android log)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +0,0 @@
|
||||
#include "bucketsort.h"
|
||||
|
||||
extern void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
|
||||
uint32_t* const ostart, uint32_t* const ostop,
|
||||
bucket_info_t *bucket_info, bucket_array_t bucket)
|
||||
{
|
||||
uint32_t *p1, *p2;
|
||||
uint32_t *start[2];
|
||||
uint32_t *stop[2];
|
||||
|
||||
start[0] = estart;
|
||||
stop[0] = estop;
|
||||
start[1] = ostart;
|
||||
stop[1] = ostop;
|
||||
|
||||
// init buckets to be empty
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
for (uint32_t j = 0x00; j <= 0xff; j++) {
|
||||
bucket[i][j].bp = bucket[i][j].head;
|
||||
}
|
||||
}
|
||||
|
||||
// sort the lists into the buckets based on the MSB (contribution bits)
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
for (p1 = start[i]; p1 <= stop[i]; p1++) {
|
||||
uint32_t bucket_index = (*p1 & 0xff000000) >> 24;
|
||||
*(bucket[i][bucket_index].bp++) = *p1;
|
||||
}
|
||||
}
|
||||
|
||||
// write back intersecting buckets as sorted list.
|
||||
// fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets.
|
||||
uint32_t nonempty_bucket;
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
p1 = start[i];
|
||||
nonempty_bucket = 0;
|
||||
for (uint32_t j = 0x00; j <= 0xff; j++) {
|
||||
if (bucket[0][j].bp != bucket[0][j].head && bucket[1][j].bp != bucket[1][j].head) { // non-empty intersecting buckets only
|
||||
bucket_info->bucket_info[i][nonempty_bucket].head = p1;
|
||||
for (p2 = bucket[i][j].head; p2 < bucket[i][j].bp; *p1++ = *p2++);
|
||||
bucket_info->bucket_info[i][nonempty_bucket].tail = p1 - 1;
|
||||
nonempty_bucket++;
|
||||
}
|
||||
}
|
||||
bucket_info->numbuckets = nonempty_bucket;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef BUCKETSORT_H__
|
||||
#define BUCKETSORT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct bucket {
|
||||
uint32_t *head;
|
||||
uint32_t *bp;
|
||||
} bucket_t;
|
||||
|
||||
typedef bucket_t bucket_array_t[2][0x100];
|
||||
|
||||
typedef struct bucket_info {
|
||||
struct {
|
||||
uint32_t *head, *tail;
|
||||
} bucket_info[2][0x100];
|
||||
uint32_t numbuckets;
|
||||
} bucket_info_t;
|
||||
|
||||
void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
|
||||
uint32_t* const ostart, uint32_t* const ostop,
|
||||
bucket_info_t *bucket_info, bucket_array_t bucket);
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Hagen Fritsch - June 2010
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interlib Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __COMMON_H
|
||||
#define __COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <at91sam7s512.h>
|
||||
typedef unsigned char byte_t;
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef ABS
|
||||
# define ABS(a) ( ((a)<0) ? -(a) : (a) )
|
||||
#endif
|
||||
|
||||
|
||||
#define RAMFUNC __attribute((long_call, section(".ramfunc")))
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
/* crapto1.h
|
||||
|
||||
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 2
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, US$
|
||||
|
||||
Copyright (C) 2008-2014 bla <blapost@gmail.com>
|
||||
*/
|
||||
#ifndef CRAPTO1_INCLUDED
|
||||
#define CRAPTO1_INCLUDED
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bucketsort.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Crypto1State {uint32_t odd, even;};
|
||||
#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free()
|
||||
void crypto1_create(struct Crypto1State *s, uint64_t key);
|
||||
#else
|
||||
struct Crypto1State *crypto1_create(uint64_t key);
|
||||
#endif
|
||||
void crypto1_destroy(struct Crypto1State*);
|
||||
void crypto1_get_lfsr(struct Crypto1State*, uint64_t*);
|
||||
uint8_t crypto1_bit(struct Crypto1State*, uint8_t, int);
|
||||
uint8_t crypto1_byte(struct Crypto1State*, uint8_t, int);
|
||||
uint32_t crypto1_word(struct Crypto1State*, uint32_t, int);
|
||||
uint32_t prng_successor(uint32_t x, uint32_t n);
|
||||
|
||||
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
|
||||
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
||||
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
|
||||
struct Crypto1State*
|
||||
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par);
|
||||
|
||||
|
||||
uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
|
||||
uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb);
|
||||
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
|
||||
int nonce_distance(uint32_t from, uint32_t to);
|
||||
extern bool validate_prng_nonce(uint32_t nonce);
|
||||
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
|
||||
uint32_t __n = 0,__M = 0, N = 0;\
|
||||
int __i;\
|
||||
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
|
||||
for(__i = FSIZE - 1; __i >= 0; __i--)\
|
||||
if(BIT(FILTER, __i) ^ evenparity32(__M & 0xFF01))\
|
||||
break;\
|
||||
else if(__i)\
|
||||
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\
|
||||
else
|
||||
|
||||
#define LF_POLY_ODD (0x29CE5C)
|
||||
#define LF_POLY_EVEN (0x870804)
|
||||
#define BIT(x, n) ((x) >> (n) & 1)
|
||||
#define BEBIT(x, n) BIT(x, (n) ^ 24)
|
||||
static inline int filter(uint32_t const x)
|
||||
{
|
||||
uint32_t f;
|
||||
|
||||
f = 0xf22c0 >> (x & 0xf) & 16;
|
||||
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
|
||||
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
|
||||
f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
|
||||
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
|
||||
return BIT(0xEC57E80A, f);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,168 +0,0 @@
|
||||
/* crypto1.c
|
||||
|
||||
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 2
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, US
|
||||
|
||||
Copyright (C) 2008-2008 bla <blapost@gmail.com>
|
||||
*/
|
||||
#include "crapto1.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "parity.h"
|
||||
|
||||
#define SWAPENDIAN(x)\
|
||||
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
|
||||
|
||||
#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free()
|
||||
void crypto1_create(struct Crypto1State *s, uint64_t key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 47;s && i > 0; i -= 2) {
|
||||
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
|
||||
s->even = s->even << 1 | BIT(key, i ^ 7);
|
||||
}
|
||||
return;
|
||||
}
|
||||
void crypto1_destroy(struct Crypto1State *state)
|
||||
{
|
||||
state->odd = 0;
|
||||
state->even = 0;
|
||||
}
|
||||
#else
|
||||
struct Crypto1State * crypto1_create(uint64_t key)
|
||||
{
|
||||
struct Crypto1State *s = malloc(sizeof(*s));
|
||||
if ( !s ) return NULL;
|
||||
|
||||
s->odd = s->even = 0;
|
||||
|
||||
int i;
|
||||
//for(i = 47;s && i > 0; i -= 2) {
|
||||
for(i = 47; i > 0; i -= 2) {
|
||||
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
|
||||
s->even = s->even << 1 | BIT(key, i ^ 7);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
void crypto1_destroy(struct Crypto1State *state)
|
||||
{
|
||||
free(state);
|
||||
}
|
||||
#endif
|
||||
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
|
||||
{
|
||||
int i;
|
||||
for(*lfsr = 0, i = 23; i >= 0; --i) {
|
||||
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
|
||||
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
|
||||
}
|
||||
}
|
||||
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
|
||||
{
|
||||
uint32_t feedin, t;
|
||||
uint8_t ret = filter(s->odd);
|
||||
|
||||
feedin = ret & !!is_encrypted;
|
||||
feedin ^= !!in;
|
||||
feedin ^= LF_POLY_ODD & s->odd;
|
||||
feedin ^= LF_POLY_EVEN & s->even;
|
||||
s->even = s->even << 1 | evenparity32(feedin);
|
||||
|
||||
t = s->odd;
|
||||
s->odd = s->even;
|
||||
s->even = t;
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted)
|
||||
{
|
||||
/*
|
||||
uint8_t i, ret = 0;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
|
||||
*/
|
||||
// unfold loop 20161012
|
||||
uint8_t ret = 0;
|
||||
ret |= crypto1_bit(s, BIT(in, 0), is_encrypted) << 0;
|
||||
ret |= crypto1_bit(s, BIT(in, 1), is_encrypted) << 1;
|
||||
ret |= crypto1_bit(s, BIT(in, 2), is_encrypted) << 2;
|
||||
ret |= crypto1_bit(s, BIT(in, 3), is_encrypted) << 3;
|
||||
ret |= crypto1_bit(s, BIT(in, 4), is_encrypted) << 4;
|
||||
ret |= crypto1_bit(s, BIT(in, 5), is_encrypted) << 5;
|
||||
ret |= crypto1_bit(s, BIT(in, 6), is_encrypted) << 6;
|
||||
ret |= crypto1_bit(s, BIT(in, 7), is_encrypted) << 7;
|
||||
return ret;
|
||||
}
|
||||
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
|
||||
{
|
||||
/*
|
||||
uint32_t i, ret = 0;
|
||||
|
||||
for (i = 0; i < 32; ++i)
|
||||
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
|
||||
*/
|
||||
//unfold loop 2016012
|
||||
uint32_t ret = 0;
|
||||
ret |= crypto1_bit(s, BEBIT(in, 0), is_encrypted) << (0 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 1), is_encrypted) << (1 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 2), is_encrypted) << (2 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 3), is_encrypted) << (3 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 4), is_encrypted) << (4 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 5), is_encrypted) << (5 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 6), is_encrypted) << (6 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 7), is_encrypted) << (7 ^ 24);
|
||||
|
||||
ret |= crypto1_bit(s, BEBIT(in, 8), is_encrypted) << (8 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 9), is_encrypted) << (9 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 10), is_encrypted) << (10 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 11), is_encrypted) << (11 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 12), is_encrypted) << (12 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 13), is_encrypted) << (13 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 14), is_encrypted) << (14 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 15), is_encrypted) << (15 ^ 24);
|
||||
|
||||
ret |= crypto1_bit(s, BEBIT(in, 16), is_encrypted) << (16 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 17), is_encrypted) << (17 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 18), is_encrypted) << (18 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 19), is_encrypted) << (19 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 20), is_encrypted) << (20 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 21), is_encrypted) << (21 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 22), is_encrypted) << (22 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 23), is_encrypted) << (23 ^ 24);
|
||||
|
||||
ret |= crypto1_bit(s, BEBIT(in, 24), is_encrypted) << (24 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 25), is_encrypted) << (25 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 26), is_encrypted) << (26 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 27), is_encrypted) << (27 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 28), is_encrypted) << (28 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 29), is_encrypted) << (29 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 30), is_encrypted) << (30 ^ 24);
|
||||
ret |= crypto1_bit(s, BEBIT(in, 31), is_encrypted) << (31 ^ 24);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* prng_successor
|
||||
* helper used to obscure the keystream during authentication
|
||||
*/
|
||||
uint32_t prng_successor(uint32_t x, uint32_t n)
|
||||
{
|
||||
SWAPENDIAN(x);
|
||||
while(n--)
|
||||
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
|
||||
|
||||
return SWAPENDIAN(x);
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Merlok - June 2011
|
||||
// Roel - Dec 2009
|
||||
// Unknown author
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Darkside hack
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "mfkey.h"
|
||||
|
||||
// MIFARE
|
||||
int compare_uint64(const void *a, const void *b) {
|
||||
if (*(uint64_t*)b == *(uint64_t*)a) return 0;
|
||||
if (*(uint64_t*)b < *(uint64_t*)a) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.
|
||||
uint32_t intersection(uint64_t *listA, uint64_t *listB) {
|
||||
if (listA == NULL || listB == NULL)
|
||||
return 0;
|
||||
|
||||
uint64_t *p1, *p2, *p3;
|
||||
p1 = p3 = listA;
|
||||
p2 = listB;
|
||||
|
||||
while ( *p1 != -1 && *p2 != -1 ) {
|
||||
if (compare_uint64(p1, p2) == 0) {
|
||||
*p3++ = *p1++;
|
||||
p2++;
|
||||
}
|
||||
else {
|
||||
while (compare_uint64(p1, p2) < 0) ++p1;
|
||||
while (compare_uint64(p1, p2) > 0) ++p2;
|
||||
}
|
||||
}
|
||||
*p3 = -1;
|
||||
return p3 - listA;
|
||||
}
|
||||
|
||||
// Darkside attack (hf mf mifare)
|
||||
// if successful it will return a list of keys, not just one.
|
||||
uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
|
||||
struct Crypto1State *states;
|
||||
uint32_t i, pos;
|
||||
uint8_t bt, ks3x[8], par[8][8];
|
||||
uint64_t key_recovered;
|
||||
uint64_t *keylist;
|
||||
|
||||
// Reset the last three significant bits of the reader nonce
|
||||
nr &= 0xFFFFFF1F;
|
||||
|
||||
for ( pos = 0; pos < 8; pos++ ) {
|
||||
ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0F;
|
||||
bt = (par_info >> (pos*8)) & 0xFF;
|
||||
|
||||
par[7-pos][0] = (bt >> 0) & 1;
|
||||
par[7-pos][1] = (bt >> 1) & 1;
|
||||
par[7-pos][2] = (bt >> 2) & 1;
|
||||
par[7-pos][3] = (bt >> 3) & 1;
|
||||
par[7-pos][4] = (bt >> 4) & 1;
|
||||
par[7-pos][5] = (bt >> 5) & 1;
|
||||
par[7-pos][6] = (bt >> 6) & 1;
|
||||
par[7-pos][7] = (bt >> 7) & 1;
|
||||
}
|
||||
|
||||
states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
|
||||
|
||||
if (!states) {
|
||||
*keys = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
keylist = (uint64_t*)states;
|
||||
|
||||
for (i = 0; keylist[i]; i++) {
|
||||
lfsr_rollback_word(states+i, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(states+i, &key_recovered);
|
||||
keylist[i] = key_recovered;
|
||||
}
|
||||
keylist[i] = -1;
|
||||
|
||||
*keys = keylist;
|
||||
return i;
|
||||
}
|
||||
|
||||
// recover key from 2 different reader responses on same tag challenge
|
||||
bool mfkey32(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s,*t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key = 0; // recovered key
|
||||
bool isSuccess = false;
|
||||
uint8_t counter = 0;
|
||||
|
||||
uint32_t p640 = prng_successor(data.nonce, 64);
|
||||
uint32_t p641 = prng_successor(data.nonce2, 64);
|
||||
s = lfsr_recovery32(data.ar ^ p640, 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, data.nr, 1);
|
||||
lfsr_rollback_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
crypto1_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_word(t, data.nr2, 1);
|
||||
if (data.ar2 == (crypto1_word(t, 0, 0) ^ p641)) {
|
||||
outkey = key;
|
||||
counter++;
|
||||
if (counter == 20) break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// recover key from 2 reader responses on 2 different tag challenges
|
||||
// skip "several found keys". Only return true if ONE key is found
|
||||
bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s, *t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key = 0; // recovered key
|
||||
bool isSuccess = false;
|
||||
int counter = 0;
|
||||
uint32_t p640 = prng_successor(data.nonce, 64);
|
||||
uint32_t p641 = prng_successor(data.nonce2, 64);
|
||||
|
||||
s = lfsr_recovery32(data.ar ^ p640, 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, data.nr, 1);
|
||||
lfsr_rollback_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
|
||||
crypto1_word(t, data.cuid ^ data.nonce2, 0);
|
||||
crypto1_word(t, data.nr2, 1);
|
||||
if (data.ar2 == (crypto1_word(t, 0, 0) ^ p641)) {
|
||||
outkey = key;
|
||||
++counter;
|
||||
if (counter == 20) break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// recover key from reader response and tag response of one authentication sequence
|
||||
int mfkey64(nonces_t data, uint64_t *outputkey){
|
||||
uint64_t key = 0; // recovered key
|
||||
uint32_t ks2; // keystream used to encrypt reader response
|
||||
uint32_t ks3; // keystream used to encrypt tag response
|
||||
struct Crypto1State *revstate;
|
||||
|
||||
// Extract the keystream from the messages
|
||||
ks2 = data.ar ^ prng_successor(data.nonce, 64);
|
||||
ks3 = data.at ^ prng_successor(data.nonce, 96);
|
||||
revstate = lfsr_recovery64(ks2, ks3);
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, data.nr, 1);
|
||||
lfsr_rollback_word(revstate, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(revstate, &key);
|
||||
crypto1_destroy(revstate);
|
||||
*outputkey = key;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Merlok - June 2011
|
||||
// Roel - Dec 2009
|
||||
// Unknown author
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Darkside hack
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef MFKEY_H
|
||||
#define MFKEY_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "mifare.h"
|
||||
#include "crapto1.h"
|
||||
|
||||
extern uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys);
|
||||
extern bool mfkey32(nonces_t data, uint64_t *outputkey);
|
||||
extern bool mfkey32_moebius(nonces_t data, uint64_t *outputkey);
|
||||
extern int mfkey64(nonces_t data, uint64_t *outputkey);
|
||||
|
||||
extern int compare_uint64(const void *a, const void *b);
|
||||
extern uint32_t intersection(uint64_t *listA, uint64_t *listB);
|
||||
|
||||
#endif
|
||||
@@ -1,271 +0,0 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <jni.h>
|
||||
#include "crapto1.h"
|
||||
#include "mfkey.h"
|
||||
#include "util_posix.h"
|
||||
#include "tools.h"
|
||||
|
||||
static volatile bool isRunning = false;
|
||||
static volatile bool stop_label = false;
|
||||
|
||||
// 32 bit recover key from 2 nonces
|
||||
int main32(int argc, char *argv[]) {
|
||||
nonces_t data = {0};
|
||||
uint32_t ks2; // keystream used to encrypt reader response
|
||||
uint64_t key; // recovered key
|
||||
|
||||
printf("MIFARE Classic key recovery - based on 32 bits of keystream\n");
|
||||
printf("Recover key from two 32-bit reader authentication answers only!\n\n");
|
||||
|
||||
if (argc != 7 && argc != 8) {
|
||||
printf(" syntax: %s <uid> <nt0> <{nr_0}> <{ar_0}> [<nt1>] <{nr_1}> <{ar_1}>\n", argv[0]);
|
||||
printf(" (you may omit nt1 if it is equal to nt0)\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool moebius_attack = (argc == 8);
|
||||
|
||||
sscanf(argv[1], "%x", &data.cuid);
|
||||
sscanf(argv[2], "%x", &data.nonce);
|
||||
data.nonce2 = data.nonce;
|
||||
sscanf(argv[3], "%x", &data.nr);
|
||||
sscanf(argv[4], "%x", &data.ar);
|
||||
if (moebius_attack) {
|
||||
sscanf(argv[5], "%x", &data.nonce2);
|
||||
sscanf(argv[6], "%x", &data.nr2);
|
||||
sscanf(argv[7], "%x", &data.ar2);
|
||||
} else {
|
||||
sscanf(argv[5], "%x", &data.nr2);
|
||||
sscanf(argv[6], "%x", &data.ar2);
|
||||
}
|
||||
|
||||
printf("Recovering key for:\n");
|
||||
printf(" uid: %08x\n", data.cuid);
|
||||
printf(" nt0: %08x\n", data.nonce);
|
||||
printf(" {nr_0}: %08x\n", data.nr);
|
||||
printf(" {ar_0}: %08x\n", data.ar);
|
||||
printf(" nt1: %08x\n", data.nonce2);
|
||||
printf(" {nr_1}: %08x\n", data.nr2);
|
||||
printf(" {ar_1}: %08x\n", data.ar2);
|
||||
|
||||
uint64_t start_time = msclock();
|
||||
|
||||
// Generate lfsr succesors of the tag challenge
|
||||
printf("\nLFSR succesors of the tag challenge:\n");
|
||||
printf(" nt': %08x\n", prng_successor(data.nonce, 64));
|
||||
printf(" nt'': %08x\n", prng_successor(data.nonce, 96));
|
||||
|
||||
// Extract the keystream from the messages
|
||||
printf("\nKeystream used to generate {ar} and {at}:\n");
|
||||
ks2 = data.ar ^ prng_successor(data.nonce, 64);
|
||||
printf(" ks2: %08x\n", ks2);
|
||||
bool success;
|
||||
if (moebius_attack) {
|
||||
success = mfkey32_moebius(data, &key);
|
||||
} else {
|
||||
success = mfkey32(data, &key);
|
||||
}
|
||||
if (success) {
|
||||
printf("Recovered key: %012"
|
||||
PRIx64
|
||||
"\n", key);
|
||||
} else {
|
||||
printf("Couldn't recover key.\n");
|
||||
}
|
||||
printf("Time spent: %1.2f seconds\n", (float) (msclock() - start_time) / 1000.0);
|
||||
}
|
||||
|
||||
jstring
|
||||
decrypt4Ints(JNIEnv *env, jobject instance,
|
||||
jint uid,
|
||||
jint nt0,
|
||||
jint nr0,
|
||||
jint ar0,
|
||||
jint nt1,
|
||||
jint nr1,
|
||||
jint ar1) {
|
||||
nonces_t data = {0};
|
||||
uint64_t key; // recovered key
|
||||
//判断是否可以忽略nt0
|
||||
bool moebius_attack = nt0 != nt1;
|
||||
data.cuid = (uint32_t) uid;
|
||||
data.nonce = (uint32_t) nt0;
|
||||
data.nonce2 = data.nonce;
|
||||
data.nr = (uint32_t) nr0;
|
||||
data.ar = (uint32_t) ar0;
|
||||
//注: 此处系命名规范问题,本人是从0下标命名!
|
||||
if (moebius_attack) {
|
||||
data.nonce2 = (uint32_t) nt1;
|
||||
data.nr2 = (uint32_t) nr1;
|
||||
data.ar2 = (uint32_t) ar1;
|
||||
} else {
|
||||
data.nr2 = (uint32_t) nr1;
|
||||
data.ar2 = (uint32_t) ar1;
|
||||
}
|
||||
bool success;
|
||||
if (moebius_attack) {
|
||||
success = mfkey32_moebius(data, &key);
|
||||
} else {
|
||||
success = mfkey32(data, &key);
|
||||
}
|
||||
if (success) {
|
||||
char ret[13] = {0};
|
||||
sprintf(ret, "%012"PRIx64, key);
|
||||
return (*env)->NewStringUTF(env, ret);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
jstring
|
||||
decrypt4Strs(JNIEnv *env, jobject instance,
|
||||
jstring uid,
|
||||
jstring nt0,
|
||||
jstring nr0,
|
||||
jstring ar0,
|
||||
jstring nt1,
|
||||
jstring nr1,
|
||||
jstring ar1) {
|
||||
//先将字符串转换为HEX字符!
|
||||
const char *uidChars = (*env)->GetStringUTFChars(env, uid, 0);
|
||||
const char *nt0Chars = (*env)->GetStringUTFChars(env, nt0, 0);
|
||||
const char *nr0Chars = (*env)->GetStringUTFChars(env, nr0, 0);
|
||||
const char *ar0Chars = (*env)->GetStringUTFChars(env, ar0, 0);
|
||||
const char *nt1Chars = (*env)->GetStringUTFChars(env, nt1, 0);
|
||||
const char *nr1Chars = (*env)->GetStringUTFChars(env, nr1, 0);
|
||||
const char *ar1Chars = (*env)->GetStringUTFChars(env, ar1, 0);
|
||||
|
||||
nonces_t data = {0};
|
||||
uint64_t key; // recovered key
|
||||
|
||||
//判断两个字符串是否为相同,也就是两个随机数是否相同!
|
||||
bool moebius_attack = strcmp(nt0Chars, nt1Chars) == 0;
|
||||
|
||||
sscanf(uidChars, "%x", &data.cuid);
|
||||
sscanf(nt0Chars, "%x", &data.nonce);
|
||||
data.nonce2 = data.nonce;
|
||||
sscanf(nr0Chars, "%x", &data.nr);
|
||||
sscanf(ar0Chars, "%x", &data.ar);
|
||||
if (moebius_attack) {
|
||||
sscanf(nt1Chars, "%x", &data.nonce2);
|
||||
sscanf(nr1Chars, "%x", &data.nr2);
|
||||
sscanf(ar1Chars, "%x", &data.ar2);
|
||||
} else {
|
||||
sscanf(nr1Chars, "%x", &data.nr2);
|
||||
sscanf(ar1Chars, "%x", &data.ar2);
|
||||
}
|
||||
|
||||
//TODO 谨记释放本地引用!避免栈溢出!
|
||||
(*env)->ReleaseStringUTFChars(env, uid, uidChars);
|
||||
(*env)->ReleaseStringUTFChars(env, nt0, nt0Chars);
|
||||
(*env)->ReleaseStringUTFChars(env, nr0, nr0Chars);
|
||||
(*env)->ReleaseStringUTFChars(env, ar0, ar0Chars);
|
||||
(*env)->ReleaseStringUTFChars(env, nt1, nt1Chars);
|
||||
(*env)->ReleaseStringUTFChars(env, nr1, nr1Chars);
|
||||
(*env)->ReleaseStringUTFChars(env, ar1, ar1Chars);
|
||||
|
||||
bool success;
|
||||
if (moebius_attack) {
|
||||
success = mfkey32_moebius(data, &key);
|
||||
} else {
|
||||
success = mfkey32(data, &key);
|
||||
}
|
||||
if (success) {
|
||||
char ret[13] = {0};
|
||||
sprintf(ret, "%012"PRIx64, key);
|
||||
return (*env)->NewStringUTF(env, ret);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 执行命令!
|
||||
* */
|
||||
jint startExecute(JNIEnv *env, jobject instance, jstring command_) {
|
||||
//初始化JNIENV,这是必须的!
|
||||
JNIEnv *tmpJniEnv = getJniEnv();
|
||||
//jboolean类型,控制是否为拷贝
|
||||
jboolean isCopy = 1;
|
||||
const char *command = (*tmpJniEnv)->GetStringUTFChars(tmpJniEnv, command_, &isCopy);
|
||||
//解析从JAVA端传入的命令
|
||||
CMD *cmd = parse_command_line(command);
|
||||
if (cmd->len < 2) {
|
||||
main32(0, cmd->cmd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
//释放内存
|
||||
(*tmpJniEnv)->ReleaseStringUTFChars(tmpJniEnv, command_, command);
|
||||
recovery_getopt_opt();
|
||||
isRunning = true;
|
||||
stop_label = false;
|
||||
printf("\n------------Begin------------\n");
|
||||
//TODO 记录开始执行的时间戳!
|
||||
time_t start_time = time(NULL);
|
||||
int ret = main32(cmd->len, cmd->cmd);
|
||||
time_t end_time = time(NULL);
|
||||
printf("\nINFO: execute time(s): %lf\n", difftime(end_time, start_time));
|
||||
printf("\n------------End------------\n");
|
||||
isRunning = false;
|
||||
stop_label = false;
|
||||
free_command_line(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 停止mfcuk
|
||||
* */
|
||||
void stopExecute(JNIEnv *env, jobject instance) {
|
||||
stop_label = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 是否在执行当中
|
||||
* */
|
||||
jboolean isExecuting(JNIEnv *env, jobject instance) {
|
||||
return (jboolean) isRunning;
|
||||
}
|
||||
|
||||
/*
|
||||
* jvm加载so时的映射回调
|
||||
* */
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *jniEnv = NULL;
|
||||
//得到当前的jvm环境指针
|
||||
if ((*vm)->GetEnv(vm, (void **) &jniEnv, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
//初始化全局的jvm函数指针
|
||||
(*jniEnv)->GetJavaVM(jniEnv, &g_JavaVM);
|
||||
//得到native函数的定义类
|
||||
jclass clazz = (*jniEnv)->FindClass(jniEnv, "cn/rrg/mfkey/NativeMfKey32");
|
||||
if (clazz == NULL) {
|
||||
return -1;
|
||||
}
|
||||
//构建和初始化函数结构体,分别是java层的函数名称,签名,对应的函数指针
|
||||
JNINativeMethod methods[] = {
|
||||
{"startExecute", "(Ljava/lang/String;)I", (void *) startExecute},
|
||||
{"isExecuting", "()Z", (void *) isExecuting},
|
||||
{"stopExecute", "()V", (void *) stopExecute},
|
||||
{"decrypt4IntParams", "(IIIIIII)Ljava/lang/String;", (void *) decrypt4Ints},
|
||||
{"decrypt4StrParams", "(Ljava/lang/String;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/String;"
|
||||
"Ljava/lang/String;)"
|
||||
"Ljava/lang/String;", (void *) decrypt4Strs}
|
||||
};
|
||||
//注册函数
|
||||
if ((*jniEnv)->RegisterNatives(jniEnv, clazz, methods, sizeof(methods) / sizeof(methods[0])) !=
|
||||
JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
//最后一定要返回jni的版本。
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "crapto1.h"
|
||||
#include "tools.h"
|
||||
#include "util_posix.h"
|
||||
|
||||
static volatile bool isRunning = false;
|
||||
static volatile bool stop_label = false;
|
||||
|
||||
int main64(int argc, char *argv[]) {
|
||||
uint32_t uid; // serial numDber
|
||||
uint32_t nt; // tag challenge
|
||||
uint32_t nr_enc; // encrypted reader challenge
|
||||
uint32_t ar_enc; // encrypted reader response
|
||||
uint32_t at_enc; // encrypted tag response
|
||||
uint64_t key = 0; // recovered key
|
||||
struct Crypto1State *revstate;
|
||||
uint32_t ks2; // keystream used to encrypt reader response
|
||||
uint32_t ks3; // keystream used to encrypt tag response
|
||||
|
||||
printf("MIFARE Classic key recovery - based on 64 bits of keystream\n");
|
||||
printf("Recover key from only one complete authentication!\n\n");
|
||||
|
||||
if (argc < 6) {
|
||||
printf(" syntax: %s <uid> <nt> <{nr}> <{ar}> <{at}> [enc] [enc...]\n\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int encc = argc - 6;
|
||||
int enclen[encc];
|
||||
uint8_t enc[encc][120];
|
||||
|
||||
sscanf(argv[1], "%x", &uid);
|
||||
sscanf(argv[2], "%x", &nt);
|
||||
sscanf(argv[3], "%x", &nr_enc);
|
||||
sscanf(argv[4], "%x", &ar_enc);
|
||||
sscanf(argv[5], "%x", &at_enc);
|
||||
for (int i = 0; i < encc; i++) {
|
||||
enclen[i] = strlen(argv[i + 6]) / 2;
|
||||
for (int i2 = 0; i2 < enclen[i]; i2++) {
|
||||
sscanf(argv[i + 6] + i2 * 2, "%2x", (unsigned int *) &enc[i][i2]);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Recovering key for:\n");
|
||||
printf(" uid: %08x\n", uid);
|
||||
printf(" nt: %08x\n", nt);
|
||||
printf(" {nr}: %08x\n", nr_enc);
|
||||
printf(" {ar}: %08x\n", ar_enc);
|
||||
printf(" {at}: %08x\n", at_enc);
|
||||
for (int i = 0; i < encc; i++) {
|
||||
printf("{enc%d}: ", i);
|
||||
for (int i2 = 0; i2 < enclen[i]; i2++) {
|
||||
printf("%02x", enc[i][i2]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\nLFSR successors of the tag challenge:\n");
|
||||
printf(" nt' : %08x\n", prng_successor(nt, 64));
|
||||
printf(" nt'': %08x\n", prng_successor(nt, 96));
|
||||
|
||||
// Extract the keystream from the messages
|
||||
ks2 = ar_enc ^ prng_successor(nt, 64);
|
||||
ks3 = at_enc ^ prng_successor(nt, 96);
|
||||
|
||||
uint64_t start_time = msclock();
|
||||
revstate = lfsr_recovery64(ks2, ks3);
|
||||
uint64_t time_spent = msclock() - start_time;
|
||||
printf("Time spent in lfsr_recovery64(): %1.2f seconds\n", (float) time_spent / 1000.0);
|
||||
printf("\nKeystream used to generate {ar} and {at}:\n");
|
||||
printf(" ks2: %08x\n", ks2);
|
||||
printf(" ks3: %08x\n", ks3);
|
||||
|
||||
// Decrypting communication using keystream if presented
|
||||
if (argc > 6) {
|
||||
printf("\nDecrypted communication:\n");
|
||||
uint8_t ks4;
|
||||
int rollb = 0;
|
||||
for (int i = 0; i < encc; i++) {
|
||||
printf("{dec%d}: ", i);
|
||||
for (int i2 = 0; i2 < enclen[i]; i2++) {
|
||||
ks4 = crypto1_byte(revstate, 0, 0);
|
||||
printf("%02x", ks4 ^ enc[i][i2]);
|
||||
rollb += 1;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
for (int i = 0; i < rollb; i++) {
|
||||
lfsr_rollback_byte(revstate, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, nr_enc, 1);
|
||||
lfsr_rollback_word(revstate, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(revstate, &key);
|
||||
crypto1_destroy(revstate);
|
||||
|
||||
printf("\nFound Key: [%012" PRIx64"]\n\n", key);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 执行命令!
|
||||
* */
|
||||
jint startExecute(JNIEnv *env, jobject instance, jstring command_) {
|
||||
//初始化JNIENV,这是必须的!
|
||||
JNIEnv *tmpJniEnv = getJniEnv();
|
||||
//jboolean类型,控制是否为拷贝
|
||||
jboolean isCopy = 1;
|
||||
const char *command = (*tmpJniEnv)->GetStringUTFChars(tmpJniEnv, command_, &isCopy);
|
||||
//解析从JAVA端传入的命令
|
||||
CMD *cmd = parse_command_line(command);
|
||||
if (cmd->len < 2) {
|
||||
main64(0, cmd->cmd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
//释放内存
|
||||
(*tmpJniEnv)->ReleaseStringUTFChars(tmpJniEnv, command_, command);
|
||||
recovery_getopt_opt();
|
||||
isRunning = true;
|
||||
stop_label = false;
|
||||
printf("\n------------Begin------------\n");
|
||||
//TODO 记录开始执行的时间戳!
|
||||
time_t start_time = time(NULL);
|
||||
int ret = main64(cmd->len, cmd->cmd);
|
||||
time_t end_time = time(NULL);
|
||||
printf("\nINFO: execute time(s): %lf\n", difftime(end_time, start_time));
|
||||
printf("\n------------End------------\n");
|
||||
isRunning = false;
|
||||
stop_label = false;
|
||||
free_command_line(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 停止mfcuk
|
||||
* */
|
||||
void stopExecute(JNIEnv *env, jobject instance) {
|
||||
stop_label = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 是否在执行当中
|
||||
* */
|
||||
jboolean isExecuting(JNIEnv *env, jobject instance) {
|
||||
return (jboolean) isRunning;
|
||||
}
|
||||
|
||||
/*
|
||||
* jvm加载so时的映射回调
|
||||
* */
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
|
||||
JNIEnv *jniEnv = NULL;
|
||||
//得到当前的jvm环境指针
|
||||
if ((*vm)->GetEnv(vm, (void **) &jniEnv, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
//初始化全局的jvm函数指针
|
||||
(*jniEnv)->GetJavaVM(jniEnv, &g_JavaVM);
|
||||
//得到native函数的定义类
|
||||
jclass clazz = (*jniEnv)->FindClass(jniEnv, "cn/rrg/mfkey/NativeMfKey64");
|
||||
if (clazz == NULL) {
|
||||
return -1;
|
||||
}
|
||||
//构建和初始化函数结构体,分别是java层的函数名称,签名,对应的函数指针
|
||||
JNINativeMethod methods[] = {
|
||||
{"startExecute", "(Ljava/lang/String;)I", (void *) startExecute},
|
||||
{"isExecuting", "()Z", (void *) isExecuting},
|
||||
{"stopExecute", "()V", (void *) stopExecute}
|
||||
};
|
||||
//注册函数
|
||||
if ((*jniEnv)->RegisterNatives(jniEnv, clazz, methods, sizeof(methods) / sizeof(methods[0])) !=
|
||||
JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
//最后一定要返回jni的版本。
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// (c) 2012 Roel Verdult
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE type prototyping
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MIFARE_H_
|
||||
#define _MIFARE_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO 14443A
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
byte_t uid[10];
|
||||
byte_t uidlen;
|
||||
byte_t atqa[2];
|
||||
byte_t sak;
|
||||
byte_t ats_len;
|
||||
byte_t ats[256];
|
||||
} __attribute__((__packed__)) iso14a_card_select_t;
|
||||
|
||||
typedef enum ISO14A_COMMAND {
|
||||
ISO14A_CONNECT = (1 << 0),
|
||||
ISO14A_NO_DISCONNECT = (1 << 1),
|
||||
ISO14A_APDU = (1 << 2),
|
||||
ISO14A_RAW = (1 << 3),
|
||||
ISO14A_REQUEST_TRIGGER = (1 << 4),
|
||||
ISO14A_APPEND_CRC = (1 << 5),
|
||||
ISO14A_SET_TIMEOUT = (1 << 6),
|
||||
ISO14A_NO_SELECT = (1 << 7),
|
||||
ISO14A_TOPAZMODE = (1 << 8),
|
||||
ISO14A_NO_RATS = (1 << 9)
|
||||
} iso14a_command_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t* response;
|
||||
size_t response_n;
|
||||
uint8_t* modulation;
|
||||
size_t modulation_n;
|
||||
uint32_t ProxToAirDuration;
|
||||
} tag_response_info_t;
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO 14443B
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
byte_t uid[10];
|
||||
byte_t uidlen;
|
||||
byte_t atqb[7];
|
||||
byte_t chipid;
|
||||
byte_t cid;
|
||||
} __attribute__((__packed__)) iso14b_card_select_t;
|
||||
|
||||
typedef enum ISO14B_COMMAND {
|
||||
ISO14B_CONNECT = (1 << 0),
|
||||
ISO14B_DISCONNECT = (1 << 1),
|
||||
ISO14B_APDU = (1 << 2),
|
||||
ISO14B_RAW = (1 << 3),
|
||||
ISO14B_REQUEST_TRIGGER = (1 << 4),
|
||||
ISO14B_APPEND_CRC = (1 << 5),
|
||||
ISO14B_SELECT_STD = (1 << 6),
|
||||
ISO14B_SELECT_SR = (1 << 7)
|
||||
} iso14b_command_t;
|
||||
|
||||
typedef enum ISO15_COMMAND {
|
||||
ISO15_CONNECT = (1 << 0),
|
||||
ISO15_NO_DISCONNECT = (1 << 1),
|
||||
ISO15_RAW = (1 << 2),
|
||||
ISO15_APPEND_CRC = (1 << 3),
|
||||
ISO15_HIGH_SPEED = (1 << 4),
|
||||
ISO15_READ_RESPONSE = (1 << 5)
|
||||
} iso15_command_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "hf 14a sim x", "hf mf sim x" attacks
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
uint32_t cuid;
|
||||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t at;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
uint8_t sector;
|
||||
uint8_t keytype;
|
||||
enum {
|
||||
EMPTY,
|
||||
FIRST,
|
||||
SECOND,
|
||||
} state;
|
||||
} nonces_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO 7618 Smart Card
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
uint8_t atr_len;
|
||||
uint8_t atr[30];
|
||||
} __attribute__((__packed__)) smart_card_atr_t;
|
||||
|
||||
typedef enum SMARTCARD_COMMAND {
|
||||
SC_CONNECT = (1 << 0),
|
||||
SC_NO_DISCONNECT = (1 << 1),
|
||||
SC_RAW = (1 << 2),
|
||||
SC_NO_SELECT = (1 << 3)
|
||||
} smartcard_command_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FeliCa
|
||||
//-----------------------------------------------------------------------------
|
||||
// IDm = ID manufacturer
|
||||
// mc = manufactureCode
|
||||
// mc1 mc2 u1 u2 u3 u4 u5 u6
|
||||
// PMm = Product manufacturer
|
||||
// icCode =
|
||||
// ic1 = ROM
|
||||
// ic2 = IC
|
||||
// maximum response time =
|
||||
// B3(request service)
|
||||
// B4(request response)
|
||||
// B5(authenticate)
|
||||
// B6(read)
|
||||
// B7(write)
|
||||
// B8()
|
||||
|
||||
// ServiceCode 2bytes (access-rights)
|
||||
// FileSystem = 1 Block = 16 bytes
|
||||
typedef struct {
|
||||
uint8_t IDm[8];
|
||||
uint8_t code[2];
|
||||
uint8_t uid[6];
|
||||
uint8_t PMm[8];
|
||||
uint8_t iccode[2];
|
||||
uint8_t mrt[6];
|
||||
uint8_t servicecode[2];
|
||||
} __attribute__((__packed__)) felica_card_select_t;
|
||||
|
||||
typedef enum FELICA_COMMAND {
|
||||
FELICA_CONNECT = (1 << 0),
|
||||
FELICA_NO_DISCONNECT = (1 << 1),
|
||||
FELICA_RAW = (1 << 3),
|
||||
FELICA_APPEND_CRC = (1 << 5),
|
||||
FELICA_NO_SELECT = (1 << 6),
|
||||
} felica_command_t;
|
||||
|
||||
#endif // _MIFARE_H_
|
||||
@@ -1,48 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// parity functions (all defined in parity.h)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <parity.h>
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t OddByteParity[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
const uint8_t EvenByteParity[256] = {
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
|
||||
};
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Parity functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// all functions defined in header file by purpose. Allows compiler optimizations.
|
||||
|
||||
#ifndef __PARITY_H
|
||||
#define __PARITY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern const uint8_t OddByteParity[256];
|
||||
|
||||
|
||||
static inline bool oddparity8(const uint8_t x) {
|
||||
return OddByteParity[x];
|
||||
}
|
||||
|
||||
|
||||
static inline bool evenparity8(const uint8_t x) {
|
||||
return !OddByteParity[x];
|
||||
}
|
||||
|
||||
|
||||
static inline bool evenparity32(uint32_t x)
|
||||
{
|
||||
#if !defined __GNUC__
|
||||
x ^= x >> 16;
|
||||
x ^= x >> 8;
|
||||
return evenparity8(x);
|
||||
#else
|
||||
return __builtin_parity(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline bool oddparity32(uint32_t x)
|
||||
{
|
||||
#if !defined __GNUC__
|
||||
x ^= x >> 16;
|
||||
x ^= x >> 8;
|
||||
return oddparity8(x);
|
||||
#else
|
||||
return !__builtin_parity(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PARITY_H */
|
||||
@@ -1,105 +0,0 @@
|
||||
//
|
||||
// Created by DXL on 2017/9/1.
|
||||
//
|
||||
|
||||
//including header
|
||||
#include <malloc.h>
|
||||
#include <tools.h>
|
||||
#include "stdbool.h"
|
||||
|
||||
//当前线程是否添加的标志位
|
||||
static bool g_IsAttach;
|
||||
|
||||
//TODO 环境变量获取函数
|
||||
JNIEnv *getJniEnv() {
|
||||
JNIEnv *currentThreadEnv;
|
||||
g_IsAttach = false;
|
||||
if ((*g_JavaVM)->GetEnv(g_JavaVM, (void **) ¤tThreadEnv, JNI_VERSION_1_4) != JNI_OK) {
|
||||
LOGE("Get Env Fail!");
|
||||
if ((*g_JavaVM)->AttachCurrentThread(g_JavaVM, ¤tThreadEnv, NULL) != JNI_OK) {
|
||||
LOGE("Attach the current thread Fail!");
|
||||
g_IsAttach = false;
|
||||
return NULL;
|
||||
} else {
|
||||
g_IsAttach = true;
|
||||
LOGE("Attach the current thread Success!");
|
||||
return currentThreadEnv;
|
||||
}
|
||||
} else {
|
||||
g_IsAttach = false;
|
||||
//LOGE("Get Env Success!");
|
||||
return currentThreadEnv;
|
||||
}
|
||||
}
|
||||
|
||||
//解绑线程env
|
||||
void deatchThread() {
|
||||
if (g_IsAttach) {
|
||||
LOGD("线程解绑成功!");
|
||||
(*g_JavaVM)->DetachCurrentThread(g_JavaVM);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO 命令行解析
|
||||
CMD *parse_command_line(const char *commandStr) {
|
||||
//一个指针,指向传进来的命令字符串(const修饰的,我们需要复刻一份!)
|
||||
CMD *cmd = (CMD *) malloc(sizeof(CMD));
|
||||
if (!cmd) {
|
||||
LOGD("申请空间失败!");
|
||||
return NULL;
|
||||
}
|
||||
//拷贝字符串到堆空间!
|
||||
char *pTmp = strdup(commandStr);
|
||||
LOGD("拷贝参数字符串到临时堆!");
|
||||
//返回的结果!先初始化为20个空间
|
||||
int size = 20;
|
||||
cmd->cmd = (char **) malloc(size * sizeof(char **));
|
||||
if (cmd->cmd) {
|
||||
LOGD("申请参数空间成功!");
|
||||
} else {
|
||||
LOGD("申请空间失败!");
|
||||
}
|
||||
//进行截取
|
||||
char *pStr = strtok(pTmp, " ");
|
||||
LOGD("第0次截取完成: %s", pStr);
|
||||
//给结果数组进行下标为0的第一次初始化
|
||||
cmd->cmd[0] = pStr;
|
||||
//局部变量用于储存解析到的命令个数,下标移动为一
|
||||
int count = 1;
|
||||
//需要截取命令参数,以空格为限定符
|
||||
for (; pStr != NULL; ++count) {
|
||||
//如果容量不够,则扩容!
|
||||
if (count == (size - 1)) {
|
||||
size += 20;
|
||||
cmd->cmd = (char **) realloc(cmd->cmd, size * sizeof(char **));
|
||||
LOGD("超过初始容量,自动扩容!");
|
||||
}
|
||||
pStr = strtok(NULL, " ");
|
||||
if (pStr) {
|
||||
cmd->cmd[count] = pStr;
|
||||
LOGD("第%d次截取完成: %s", count, pStr);
|
||||
}
|
||||
}
|
||||
cmd->len = (count - 1);
|
||||
LOGD("解析函数执行完成!");
|
||||
return cmd;
|
||||
}
|
||||
|
||||
//内存释放
|
||||
void free_command_line(CMD *cmd) {
|
||||
//二级指针需要逐层释放!
|
||||
LOGD("释放命令行字符串二级引用!");
|
||||
free(cmd->cmd[0]);
|
||||
LOGD("释放命令行一级引用!");
|
||||
free(cmd->cmd);
|
||||
LOGD("释放结构体内存");
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
//重置getopt函数的参数
|
||||
void recovery_getopt_opt() {
|
||||
optind = 0;
|
||||
opterr = 1;
|
||||
optopt = 0;
|
||||
optarg = NULL;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user