Created
October 27, 2011 17:10
-
-
Save vmlemon/1320161 to your computer and use it in GitHub Desktop.
Modified GSM CardPeek script (UMTS)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- | |
| -- This file is part of Cardpeek, the smartcard reader utility. | |
| -- | |
| -- Copyright 2009-2011 by 'L1L1' | |
| -- | |
| -- Cardpeek 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. | |
| -- | |
| -- Cardpeek 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 Cardpeek. If not, see <http://www.gnu.org/licenses/>. | |
| -- | |
| require('lib.strict') | |
| require('lib.apdu') | |
| require('lib.treeflex') | |
| card.CLA = 0xA0 | |
| function card.get_response(len) | |
| return card.send(bytes.new(8,card.CLA,0xC0,0x00,0x00,len)) | |
| end | |
| function card.gsm_select(file_path,return_what,length) | |
| local sw,resp = card.select(file_path,return_what,length) | |
| if bit.AND(sw,0xFF00)==0x9F00 then | |
| log.print(log.INFO,"GSM specific response code 9Fxx") | |
| sw,resp = card.get_response(bit.AND(sw,0xFF)) | |
| end | |
| return sw,resp | |
| end | |
| BCD_EXTENDED = { "0", "1", "2", "3", | |
| "4", "5", "6", "7", | |
| "8", "9", "*", "#", | |
| "-", "?", "!", "F" } | |
| function GSM_bcd_swap(data) | |
| local i | |
| local msb, lsb | |
| local r = "" | |
| for i=0,#data-1 do | |
| lsb = bit.AND(data[i],0xF) | |
| msb = bit.SHR(data[i],4) | |
| if lsb == 0xF then break end | |
| r = r .. BCD_EXTENDED[1+lsb] | |
| if msb == 0xF then break end | |
| r = r .. BCD_EXTENDED[1+msb] | |
| end | |
| return r | |
| end | |
| function GSM_tostring(data) | |
| local r = "" | |
| local i | |
| for i=0,#data-1 do | |
| if data[i]==0xFF then | |
| return r | |
| end | |
| r = r .. string.char(data[i]) | |
| end | |
| return r | |
| end | |
| ------------------------------------------------------------------------- | |
| AC_GSM = { "Always", "CHV1", "CHV2", "RFU", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "ADM", | |
| "ADM", "ADM", "ADM", "Never" } | |
| MAP1_FILE_STRUCT = { [0]="transparent", [1]="linear fixed", [3]="cyclic" } | |
| MAP1_FILE_TYPE = { [1]="MF", [2]="DF", [4]="EF" } | |
| MAP1_FILE_STATUS = { [0]="invalidated", [1]="not invalidated" } | |
| function GSM_access_conditions(node,data) | |
| local text | |
| text = AC_GSM[1+bit.SHR(data[0], 4)] .. "," | |
| .. AC_GSM[1+bit.AND(data[0],0xF)] .. "," | |
| .. AC_GSM[1+bit.SHR(data[1], 4)] .. "," | |
| -- RFU: .. AC_GSM[1+bit.AND(data[1],0xF)] .. "," | |
| .. AC_GSM[1+bit.SHR(data[2], 4)] .. "," | |
| .. AC_GSM[1+bit.AND(data[2],0xF)] | |
| return node:setAlt(text) | |
| end | |
| function GSM_byte_map(node,data,map) | |
| return node:setAlt(map[bytes.tonumber(data)]) | |
| end | |
| function GSM_ICCID(node,data) | |
| return node:setAlt(GSM_bcd_swap(data)) | |
| end | |
| function GSM_SPN(node,data) | |
| return node:setAlt(GSM_tostring(bytes.sub(data,1))) | |
| end | |
| function GSM_ADN(node,data) | |
| local alpha_len = #data-14 | |
| local r = "" | |
| if data[0]==0xFF then | |
| return false | |
| end | |
| if alpha_len then | |
| r = GSM_tostring(bytes.sub(data,0,alpha_len-1)) | |
| end | |
| r = r .. ": " .. GSM_bcd_swap(bytes.sub(data,alpha_len+2,alpha_len+12)) | |
| return node:setAlt(r) | |
| end | |
| GSM_MAP = | |
| { "application", "3F00", "MF", { | |
| { "file", "2FE2", "ICCID", GSM_ICCID }, | |
| { "file", "2F05", "PL", nil }, | |
| { "file", "2F06", "ARR", nil }, | |
| { "application", "7F10", "TELECOM", { | |
| { "file", "6F3A", "ADN", GSM_ADN }, | |
| { "file", "6F3B", "FDN", nil }, | |
| { "file", "6F3C", "SMS", nil }, | |
| { "file", "6F3D", "CCP", nil }, | |
| { "file", "6F40", "MSISDN", nil }, | |
| { "file", "6F42", "SMSP", nil }, | |
| { "file", "6F43", "SMSS", nil }, | |
| { "file", "6F47", "SMSR", nil}, | |
| { "file", "6F44", "LND", nil }, | |
| { "file", "6F49", "SDN", nil }, | |
| { "file", "6F4A", "EXT1", nil }, | |
| { "file", "6F4B", "EXT2", nil }, | |
| { "file", "6F58", "CMI", nil}, | |
| { "file", "4F20", "IMG", nil}, | |
| } | |
| }, | |
| { "application", "5F50", "GRAPHICS", { | |
| { "file", "4F20", "IMG", nil }, | |
| } | |
| }, | |
| { "application", "7F50", "UMTS", { | |
| { "file", "6FE0", "CHV", nil }, | |
| { "file", "6FE1", "CK", nil}, | |
| { "file", "6FE2", "IK", nil}, | |
| { "file", "6FE3", "IMUI", nil}, | |
| { "file", "6FE4", "SPID", nil}, | |
| { "file", "6FE5", "SSD", nil}, | |
| } | |
| }, | |
| { "application", "7F20", "GSM", { | |
| { "file", "6F05", "LP", nil }, | |
| { "file", "6F07", "IMSI", nil }, | |
| { "file", "6F20", "Kc", nil }, | |
| { "file", "6F52", "KcGPRS", nil}, | |
| { "file", "6F30", "PLMNsel", nil }, | |
| { "file", "6F31", "HPLMN", nil }, | |
| { "file", "6F37", "ACMmax", nil }, | |
| { "file", "6F38", "SST", nil }, | |
| { "file", "6F39", "ACM", nil }, | |
| { "file", "6F3E", "GID1", nil }, | |
| { "file", "6F3F", "GID2", nil }, | |
| { "file", "6F41", "PUCT", nil }, | |
| { "file", "6F45", "CBMI", nil }, | |
| { "file", "6F46", "SPN", GSM_SPN }, | |
| { "file", "6F74", "BCCH", nil }, | |
| { "file", "6F78", "ACC", nil }, | |
| { "file", "6F7B", "FPLMN", nil }, | |
| { "file", "6F7E", "LOCI", nil }, | |
| { "file", "6F53", "LOCIGPRS", nil}, | |
| { "file", "6FAD", "AD", nil }, | |
| { "file", "6FAE", "PHASE", nil }, | |
| }, | |
| } | |
| } | |
| } | |
| DF_MAP = | |
| { | |
| { 2, "RFU" }, | |
| { 2, "Total memory"}, | |
| { 2, "File ID" }, | |
| { 1, "Type of file" }, | |
| { 5, "RFU" }, | |
| { 1, "Length of extra GSM data" }, | |
| { 1, "File characteristics" }, | |
| { 1, "Number of DFs in this DF" }, | |
| { 1, "Number of EFs in this DF" }, | |
| { 1, "Number of CHVs" }, | |
| { 1, "RFU" }, | |
| { 1, "CHV1 status" }, | |
| { 1, "UNBLOCK CHV1 status" }, | |
| { 1, "CHV2 status" }, | |
| { 1, "UNBLOCK CHV2 status" }, | |
| } | |
| EF_MAP = | |
| { | |
| { 2, "RFU" }, | |
| { 2, "File size" }, | |
| { 2, "File ID" }, | |
| { 1, "File type", GSM_byte_map, MAP1_FILE_TYPE }, | |
| { 1, "Command flags" }, | |
| { 3, "Access conditions", GSM_access_conditions }, | |
| { 1, "File status", GSM_byte_map, MAP1_FILE_STATUS }, | |
| { 1, "Length of extra GSM data" }, | |
| { 1, "File structure", GSM_byte_map, MAP1_FILE_STRUCT }, | |
| { 1, "Length of a record" }, | |
| } | |
| function gsm_map_descriptor(node,data,map) | |
| local pos = 0 | |
| local i,v | |
| local item | |
| node = node:append("record","header",nil,#data) | |
| for i,v in ipairs(map) do | |
| item = bytes.sub(data,pos,pos+v[1]-1) | |
| child = node:append("item",v[2],nil,v[1]):setVal(item) | |
| if v[3] then | |
| v[3](child,item,v[4]) | |
| end | |
| pos = pos + v[1] | |
| end | |
| end | |
| function gsm_read_content_binary(node,fsize,alt) | |
| local pos = 0 | |
| local try_read | |
| local sw,resp | |
| local data = bytes.new(8) | |
| while fsize>0 do | |
| if fsize>128 then | |
| try_read = 128 | |
| else | |
| try_read = fsize | |
| end | |
| sw, resp = card.read_binary('.',pos,try_read) | |
| if sw~=0x9000 then | |
| return false | |
| end | |
| bytes.append(data,resp) | |
| pos = pos + try_read | |
| fsize = fsize - try_read | |
| end | |
| node = node:append("record","data",nil,#data):setVal(data) | |
| if alt then | |
| alt(node,data) | |
| end | |
| return true | |
| end | |
| function gsm_read_content_record(node,fsize,rec_len,alt) | |
| local rec_count | |
| local rec_num | |
| local sw,resp | |
| local record | |
| if rec_len==nil or rec_len==0 then | |
| return false | |
| end | |
| rec_count = fsize/rec_len | |
| for rec_num=1,rec_count do | |
| sw, resp = card.read_record('.',rec_num,rec_len) | |
| if sw~=0x9000 then | |
| return false | |
| end | |
| record = node:append("record","record",rec_num,rec_len):setVal(resp) | |
| if alt then | |
| alt(record,resp) | |
| end | |
| end | |
| return true | |
| end | |
| function gsm_map(root,amap) | |
| local i,v | |
| local sw,resp | |
| local child | |
| local file_type | |
| local file_size | |
| sw, resp = card.gsm_select("#"..amap[2]) | |
| if sw == 0x9000 then | |
| child = root:append(amap[1],amap[3],amap[2]) | |
| if amap[1]=="file" then | |
| gsm_map_descriptor(child,resp,EF_MAP) | |
| file_type = resp[13] | |
| file_size = resp[2]*256+resp[3] | |
| if file_type == 0 then | |
| gsm_read_content_binary(child,file_size,amap[4]) | |
| else | |
| gsm_read_content_record(child,file_size,resp[14],amap[4]) | |
| end | |
| else | |
| gsm_map_descriptor(child,resp,DF_MAP) | |
| if amap[4] then | |
| for i,v in ipairs(amap[4]) do | |
| gsm_map(child,v) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| function pin_wrap(pin) | |
| local i | |
| local r = bytes.new(8) | |
| for i=1,#pin do | |
| bytes.append(r,string.byte(pin,i)) | |
| end | |
| for i=#pin+1,8 do | |
| bytes.append(r,0xFF) | |
| end | |
| return r | |
| end | |
| local PIN | |
| local sw,resp | |
| if card.connect() then | |
| CARD = card.tree_startup("GSM") | |
| sw,resp = card.send(bytes.new(8,"A0 A4 00 00 02 7F 50")) -- select DF GSM | |
| log.print(log.INFO,"Testing if response code starts with 9F") | |
| if bit.AND(sw,0xFF00) == 0x9F00 then | |
| -- if bit == 0x9404 then | |
| PIN = ui.readline("Enter PIN for verification (or keep empty to avoid PIN verification)",8,"0000") | |
| if PIN~="" then | |
| PIN= pin_wrap(PIN) | |
| card.send(bytes.new(8,"A0 20 00 01 08",PIN)) -- unblock pin = 0000 | |
| end | |
| gsm_map(_(CARD),GSM_MAP) | |
| else | |
| print(sw,resp) | |
| ui.question("This does not seem to be a GSM SIM card, halting.",{"OK"}) | |
| end | |
| card.disconnect() | |
| end | |
| log.print(log.WARNING,"NOTE: This GSM script is still incomplete.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment