diff --git a/client/libluamiibo.so b/client/libluamiibo.so new file mode 100644 index 000000000..2cd716aa0 Binary files /dev/null and b/client/libluamiibo.so differ diff --git a/client/lualibs/amiibolib.lua b/client/lualibs/amiibolib.lua new file mode 100644 index 000000000..c5cccb81c --- /dev/null +++ b/client/lualibs/amiibolib.lua @@ -0,0 +1,90 @@ +local luamiibo_open, err = package.loadlib("./libluamiibo.so", "luaopen_luamiibo") + +if err then + print(err) + return +end + +local luamiibo = luamiibo_open() + +local FLAG_SETTINGS_INITIALIZED = 4 +local FLAG_APPDATA_INITIALIZED = 3 + +local Amiibo = {} +Amiibo.__index = Amiibo + +function Amiibo:new (o) + o = o or {} + setmetatable(o, self) + + if o.tag ~= nil then + o:load_tag(o.tag) + end + return o +end + +function Amiibo:load_tag (tag) + self.plain = luamiibo.unpack(tag) + + -- UID + local raw_uid = string.sub(self.plain, 469, 469 + 8) + self.uid = string.sub(raw_uid, 1, 3) .. string.sub(raw_uid, 5, 8) + + -- Settings + local count, flags = bin.unpack('C', string.sub(self.plain, 45, 45)) + self.setting_flags = flags + self.settings_initialized = self:check_flag(FLAG_SETTINGS_INITIALIZED) + self.appdata_initialized = self:check_flag(FLAG_APPDATA_INITIALIZED) + + local _, appdatacounter = bin.unpack('>S', string.sub(self.plain, 49, 50)) + self.appdata_counter = appdatacounter + + self.figure_id = string.sub(self.plain, 477, 477 + 8) + + -- UTF-16 nickname string + self.nickname = string.sub(self.plain, 57, 76) +end + + +function Amiibo:export_tag () + return luamiibo.pack(self.plain) +end + + +function Amiibo:check_flag (power) + local flag = math.pow(2, power) + return flag == bit32.band(self.setting_flags, flag) +end + + +function Amiibo:get_pwd () + local xorkey = "\xaa\x55\xaa\x55" + + local result = '' + for i = 1, 4 do + result = result .. + bin.pack('C', + bit32.bxor(self.uid:byte(i+1), + self.uid:byte(i+3), + xorkey:byte(i))) + end + + return result +end + +-- Hack to make UTF-16 nicknames into regular char string +-- Only works for ASCII nicknames +function Amiibo:display_nickname() + local nickname_tmp = self.nickname + + local nickname = '' + for i = 1, nickname_tmp:len() do + if i % 2 == 0 then + nickname = nickname .. nickname_tmp:sub(i, i) + end + end + + return nickname +end + +return Amiibo diff --git a/client/lualibs/emulator.lua b/client/lualibs/emulator.lua new file mode 100644 index 000000000..36ef38ac1 --- /dev/null +++ b/client/lualibs/emulator.lua @@ -0,0 +1,84 @@ +local cmds = require('commands') +local utils = require('utils') +local reader = require('read14a') + +local Emulator = { + _VERSION = 'emulator.lua 0.1.0', + _DESCRIPTION = 'emulator memory interface', + BLOCK_SZ = 512, + BLOCK_COUNT = 512 / 16 +} + +function Emulator:set_mem (data, clear_first) + if clear_first then + -- Clear out the emulator memory first + local emuMemclearCmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMCLR, arg1 = 0, arg2 = 0, arg3 = 0} + + local _, err = reader.sendToDevice(emuMemclearCmd) + if err then + print('Failed to clear emulator memory:', err) + return false + else + print('Cleared emulator memory') + end + end + + -- Can fit 32 16 byte blocks per command (512 total bytes max) + for i = 0, (data:len() / self.BLOCK_SZ) do + local cur_out_block = data:sub((i*self.BLOCK_SZ) + 1, (i*self.BLOCK_SZ) + self.BLOCK_SZ) + print(string.format('Transmission #%u: %u bytes', i, cur_out_block:len())) + + -- arg1: start block number + -- arg2: block count + local emuMemsetCmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, + data = utils.hexlify(cur_out_block), + arg1 = i * self.BLOCK_COUNT, + arg2 = self.BLOCK_COUNT} + + -- Send command and wait for response + local _, err = reader.sendToDevice(emuMemsetCmd) + if err then + print('Failed setting memory', err) + return false + end + end + + print('Emulator memory set') + return true +end + +-- Read bytes from emulator memory +function Emulator:get_mem (size) + local MAX_BLOCKS = 4 + local result = '' + + -- We can request a maximum of 4 blocks (16 bytes each) per command, + -- according to mifarecmd.c + for i = 0, (size / (MAX_BLOCKS * 16)) do + -- arg1: start block number + -- arg2: block count (max 4) + local emuMemGetCmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMGET, + arg1 = i * MAX_BLOCKS, + arg2 = MAX_BLOCKS, + arg3 = 0} + + local response, err = reader.sendToDevice(emuMemGetCmd) + if err then + print('Failed getting memory:', err) + return false + end + + -- USB data begins after four 64-bit values + local data_begin = ((64/8) * 4) + 1 + response = string.sub(response, data_begin) + + -- Truncate to the received 16 byte blocks + response = string.sub(response, 1, 16 * MAX_BLOCKS) + + result = result .. response + end + + return string.sub(result, 1, size) +end + +return Emulator