Skip to content

Commit

Permalink
Close #95: demo page for xiaomi watch to clone mf1 (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
taichunmin authored Jun 12, 2024
2 parents a667e7e + 8491527 commit 5af3f82
Show file tree
Hide file tree
Showing 6 changed files with 557 additions and 56 deletions.
34 changes: 25 additions & 9 deletions pages/demos.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
- [Related links](#related-links)
- [mifare1k.html](#mifare1khtml)
- [Features](#features-2)
- [mifare-value.html](#mifare-valuehtml)
- [mifare-xiaomi.html](#mifare-xiaomihtml)
- [Features](#features-3)
- [mifare-value.html](#mifare-valuehtml)
- [Features](#features-4)

## [device-settings.html](https://taichunmin.idv.tw/chameleon-ultra.js/device-settings.html)

Expand Down Expand Up @@ -57,22 +59,36 @@ A ChameleonUltra tool for mifare class 1k.

### Features

- Load/Emulate from slot of ChameleonUltra.
- Read/Write from Mifare Gen1a Tag (UID).
- Read/Write from Mifare Classic 1k, Gen2 Tag (CUID, FUID, UFUID).
- Import/Export from `.json`, `.bin`, `.eml`, `.mct` files.
- Load/Emulate for slot of ChameleonUltra.
- Read/Write for Mifare Gen1a Tag (UID).
- Read/Write for Mifare Classic 1k, Gen2 Tag (CUID, FUID, UFUID).
- Import/Export dump for `.json`, `.bin`, `.eml`, `.mct` files.

- - -

## [mifare-value.html](https://taichunmin.idv.tw/chameleon-ultra.js/mifare-value.html)
## [mifare-xiaomi.html](https://taichunmin.idv.tw/chameleon-ultra.js/mifare-xiaomi.html)

![](https://i.imgur.com/jJ3pNvn.png)
A tool for Xiaomi Watch to clone encrypted Mifare Classic tag.

![](https://i.imgur.com/M39Y0Be.png)

### Features

- Import/Export dump for `.json`, `.bin`, `.eml`, `.mct` files.
- Emulate ChameleonUltra as non-encrypted Mifare Classic tag.
- Write/Verify/Read for Xiaomi Watch.

- - -

## [mifare-value.html](https://taichunmin.idv.tw/chameleon-ultra.js/mifare-value.html)

在台灣有些 MIFARE Classic 卡片使用 value block 來儲存卡片的餘額,但是有些中國魔術卡不支援 value block 指令,所以無法使用這些魔術卡來複製 MIFARE Classic 卡片。這個工具可以讓你測試卡片是否支援 value block 指令。

A ChameleonUltra tool for MIFARE Classic value block commands. Some MIFARE Classic cards in Taiwan are using value block to store the balance of the card. But some chinese magic cards didn't support value block commands. So you can't use these magic cards to clone original MIFARE Classic cards. This tool can help you to test whether the card support value block commands or not.

![](https://i.imgur.com/jJ3pNvn.png)

### Features

- Get/Set mifare value block
- Increase/Decrease/Restore mifare value block
- Get/Set for mifare value block
- Increase/Decrease/Restore for mifare value block
16 changes: 8 additions & 8 deletions pug/src/device-settings.pug
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ block script
})
},
async btnLoadDevice () {
const { ultra } = this
try {
this.showLoading({ text: 'Loading settings...' })
const { ultra } = this
const batteryInfo = await ultra.cmdGetBatteryInfo()
const ss = {
animationMode: await ultra.cmdGetAnimationMode(),
Expand All @@ -204,14 +204,14 @@ block script
this.$set(this, 'ss', { ...this.ss, ...ss, blePairingKeyVisible: false })
Swal.close()
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', text: err.message })
}
},
async btnSaveDevice () {
const { ultra } = this
try {
this.showLoading({ text: 'Saving settings...' })
const { ultra } = this
const ss = await joiDeviceSettings.validateAsync(this.ss, { stripUnknown: true })
await ultra.cmdSetAnimationMode(ss.animationMode)
await ultra.cmdBleSetPairingMode(ss.blePairingMode)
Expand All @@ -225,25 +225,25 @@ block script
await ultra.cmdSaveSettings()
await Swal.fire({ icon: 'success', text: 'Settings save successfully!' })
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', text: err.message })
}
},
async btnEnterBootloader () {
if (!await this.confirm('Enter bootloader?', 'Yes', 'Cancel')) return
await this.ultra.cmdEnterBootloader().catch(console.error)
await this.ultra.cmdEnterBootloader().catch(err => { this.ultra.emitter.emit('error', err) })
},
async btnResetSettings () {
if (!await this.confirm('Reset to default settings?', 'Yes', 'Cancel')) return
await this.ultra.cmdResetSettings().catch(console.error)
await this.ultra.cmdResetSettings().catch(err => { this.ultra.emitter.emit('error', err) })
},
async btnBleDeleteAllBonds () {
if (!await this.confirm('Delete ALL BLE bonds?', 'Yes', 'Cancel')) return
await this.ultra.cmdBleDeleteAllBonds().catch(console.error)
await this.ultra.cmdBleDeleteAllBonds().catch(err => { this.ultra.emitter.emit('error', err) })
},
async btnWipeFds () {
if (!await this.confirm('Factory reset?', 'Yes', 'Cancel')) return
await this.ultra.cmdWipeFds().catch(console.error)
await this.ultra.cmdWipeFds().catch(err => { this.ultra.emitter.emit('error', err) })
},
async confirm (text, confirmButtonText, cancelButtonText) {
return await new Promise((resolve, reject) => {
Expand Down
16 changes: 8 additions & 8 deletions pug/src/mfkey32.pug
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ block script
})
},
async btnScanTag () {
const { ultra } = this
try {
this.showLoading({ text: 'Scanning tag...' })
const { ultra } = this
const slot = await ultra.cmdSlotGetActive()
const tag1 = _.first(await ultra.cmdHf14aScan())
await ultra.cmdChangeDeviceMode(DeviceMode.TAG)
Expand All @@ -176,13 +176,13 @@ block script
_.merge(this.ss, tag2)
Swal.close()
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to scan tag.', text: err.message })
}
},
async btnEmulateTag () {
const { ultra } = this
try {
const { ultra } = this
const { atqa, sak, slot, tagType, uid } = this.ss
console.log({ atqa, sak, slot, tagType, uid })
const slotName = await ultra.cmdSlotGetFreqName(slot, FreqType.HF) ?? '(no name)'
Expand Down Expand Up @@ -214,19 +214,19 @@ block script
await ultra.cmdSlotSaveSettings()
await Swal.fire({ icon: 'success', title: 'Emulate successfully!' })
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to emulate tag.', text: err.message })
}
},
async btnRecover () {
const { ultra } = this
try {
const swalCfg = {
text: 'Connecting device...',
progressSteps: ['1', '2', '3'],
currentProgressStep: 0,
}
this.showLoading(swalCfg)
const { ultra } = this
const logCnt = await ultra.cmdMf1GetDetectionCount()
if (logCnt < 2) throw new Error('Please let reader to read ChameleonUltra more than 2 times to collect data.')

Expand Down Expand Up @@ -278,14 +278,14 @@ block script
}
await Swal.fire({ icon: 'success', title: 'Recover successfully!' })
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to recover key.', text: err.message })
}
},
async btnCheck () {
const { ultra } = this
try {
this.showLoading({ text: 'Checking key...' })
const { ultra } = this
const { block, keyType, key } = this.ss
const isCorrect = await ultra.cmdMf1CheckBlockKey({
block,
Expand All @@ -296,7 +296,7 @@ block script
if (!isCorrect) return await Swal.fire({ icon: 'error', title: 'Key is incorrect!' })
await Swal.fire({ icon: 'success', title: 'Key is correct!' })
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to check key.', text: err.message })
}
},
Expand Down
13 changes: 7 additions & 6 deletions pug/src/mifare-value.pug
Original file line number Diff line number Diff line change
Expand Up @@ -139,43 +139,44 @@ block script
})
},
async cmdVblockGet (src) {
const { ultra } = this
src = this.mf1ParseBlockKey(src)
const ultra = this.ultra
const res = await ultra.mf1VblockGetValue(src)
await Swal.fire({ icon: 'success', title: 'Success', text: `block[${src.block}] = ${JSON.stringify(res)}` })
},
async btnGetValue () {
const { ultra } = this
try {
this.showLoading({ text: 'Processing...' })
await this.cmdVblockGet(this.ss.src)
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to get value from src', text: err.message })
}
},
async btnSetValue () {
const { ultra } = this
try {
this.showLoading({ text: 'Processing...' })
const src = this.mf1ParseBlockKey(this.ss.src)
const ultra = this.ultra
await ultra.mf1VblockSetValue(src, { adr: src.block, value: this.ss.operand })
await this.cmdVblockGet(this.ss.src)
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: 'Failed to set value to src', text: err.message })
}
},
async btnManipulateValue (operator) {
const { ultra } = this
try {
this.showLoading({ text: 'Processing...' })
const src = this.mf1ParseBlockKey(this.ss.src)
const dst = this.ss.srcAsDst ? src : this.mf1ParseBlockKey(this.ss.dst)
const operand = this.ss.operand
const ultra = this.ultra
await ultra.cmdMf1VblockManipulate(src, operator, operand, dst)
await this.cmdVblockGet(this.ss.src)
} catch (err) {
console.error(err)
ultra.emitter.emit('error', err)
await Swal.fire({ icon: 'error', title: `Failed to ${Mf1VblockOperator[operator]} value`, text: err.message })
}
},
Expand Down
Loading

0 comments on commit 5af3f82

Please sign in to comment.