Class: HardsploitAPI

Inherits:
Object
  • Object
show all
Includes:
USB, USB_COMMAND, USB_STATE
Defined in:
lib/HardsploitAPI/HardsploitAPI_I2C.rb,
lib/HardsploitAPI/HardsploitAPI.rb,
lib/HardsploitAPI/HardsploitAPI_SPI.rb,
lib/HardsploitAPI/HardsploitAPI_ERROR.rb,
lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb,
lib/HardsploitAPI/HardsploitAPI_CONSTANT.rb,
lib/HardsploitAPI/HardsploitAPI_FIRMWARE.rb,
lib/HardsploitAPI/HardsploitAPI_PROGRESS.rb,
lib/HardsploitAPI/HardsploitAPI_TEST_INTERACT.rb,
lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb,
lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb

Overview

Hardsploit API - By Opale Security
www.opale-security.com || www.hardsploit.io
License: GNU General Public License v3
License URI: http://www.gnu.org/licenses/gpl.txt

Defined Under Namespace

Modules: Error, I2C, USB, USB_COMMAND, USB_STATE, VERSION Classes: HardsploitProgress

Constant Summary

Constants included from USB_COMMAND

USB_COMMAND::ERASE_FIRMWARE, USB_COMMAND::FPGA_COMMAND, USB_COMMAND::FPGA_DATA, USB_COMMAND::GET_SERIAL_NUMBER, USB_COMMAND::GET_VERSION_NUMBER, USB_COMMAND::GREEN_LED, USB_COMMAND::LOOPBACK, USB_COMMAND::READ_ID_FLASH, USB_COMMAND::READ_PAGE_FIRMWARE, USB_COMMAND::RED_LED, USB_COMMAND::START_FPGA, USB_COMMAND::START_FPGA_DATA, USB_COMMAND::STOP_FPGA, USB_COMMAND::STOP_FPGA_DATA, USB_COMMAND::VCP_ERROR, USB_COMMAND::WRITE_PAGE_FIRMWARE

Constants included from USB_STATE

USB_STATE::BUSY, USB_STATE::CONNECTED, USB_STATE::ERROR_SEND, USB_STATE::NOT_CONNECTED, USB_STATE::PACKET_IS_TOO_LARGE, USB_STATE::SUCCESSFUL_RECEIVE, USB_STATE::SUCCESSFUL_SEND, USB_STATE::TIMEOUT_RECEIVE, USB_STATE::UNKNOWN_CONNECTED, USB_STATE::UNKNOWN_STATE

Constants included from USB

USB::IN_ENDPOINT, USB::OUT_ENDPOINT, USB::USB_TRAME_SIZE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ HardsploitAPI

  • callbackSpeedOfTransfert

    callback to get back information about speed



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 36

def initialize(*args)
  parametters = HardsploitAPI.checkParametters(["callbackData","callbackInfo","callbackProgress","callbackSpeedOfTransfert"],args)
  @callbackData = parametters[:callbackData]
  @callbackInfo = parametters[:callbackInfo]
  @callbackProgress = parametters[:callbackProgress]
  @callbackSpeedOfTransfert = parametters[:callbackSpeedOfTransfert]

  @packet_send = Array.new
  @usb = LIBUSB::Context.new
  @device = nil
end

Instance Attribute Details

#debugPortObject

Returns the value of attribute debugPort.



12
13
14
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 12

def debugPort
  @debugPort
end

#devObject

Returns the value of attribute dev.



25
26
27
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 25

def dev
  @dev
end

#stm32Object

Returns the value of attribute stm32.



13
14
15
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 13

def stm32
  @stm32
end

Class Method Details

.BytesToInt(*args) ⇒ Object

Obtain high byte of a word

  • lByte

    low byte

  • hByte

    high byte

Return 16 bits integer concatenate with low and high bytes



70
71
72
73
74
75
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 70

def self.BytesToInt(*args)
  parametters = HardsploitAPI.checkParametters(["lByte","hByte"],args)
  lByte = parametters[:lByte]
  hByte = parametters[:hByte]
  return (lByte + (hByte<<8))
end

.checkParametters(arr_parametters, *args) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 96

def self.checkParametters(arr_parametters,*args)
  params = Hash.new
  if args[0][0].class == Hash then
    hash_args = args[0][0]
      arr_parametters.each  do |param|
        if hash_args[param.to_sym] == nil then
            raise "Wrong parametters, you need to specify #{param.to_sym}"
        else
            params[param.to_sym] = hash_args[param.to_sym]
        end
      end
  else
    if args[0].length == arr_parametters.size then
        args[0].each_with_index do |value,key|
          params[arr_parametters[key].to_sym] = value
        end
    else
      raise "Error : method need #{arr_parametters.size} parametters"
    end
  end
  return params
end

.highByte(*args) ⇒ Object

Obtain high byte of a word

  • word

    16 bit word

Return high byte of the word



60
61
62
63
64
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 60

def self.highByte(*args)
  parametters = HardsploitAPI.checkParametters(["word"],args)
  word = parametters[:word]
  return  (word & 0xFF00) >> 8
end

.lowByte(*args) ⇒ Object

Obtain low byte of a word

  • word

    16 bit word

Return low byte of the word



51
52
53
54
55
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 51

def self.lowByte(*args)
  parametters = HardsploitAPI.checkParametters(["word"],args)
  word = parametters[:word]
  return  word & 0xFF
end

.reverseBit(byte) ⇒ Object



92
93
94
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 92

def self.reverseBit(byte)
  return byte.to_s(2).rjust(8, "0").reverse.to_i(2)
end

Instance Method Details

#calcOpcode(ap, register, read) ⇒ Object



239
240
241
242
243
244
245
246
247
248
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 239

def calcOpcode (ap, register, read)
    opcode = 0x00
    (ap ? opcode |= 0x40 : opcode |= 0x00)
    (read ? opcode |= 0x20 : opcode |= 0x00)
    opcode = opcode | ((register & 0x01) << 4) | ((register & 0x02) << 2) #Addr AP DP  bit 2..3
    opcode = opcode | (((opcode & 0x78).to_s(2).count('1').odd? ? 1 : 0) << 2)  #0x78 mask to take only read ap and register to process parity bit
    opcode = opcode | 0x81 #Start and Park Bit
    #puts "OpCode #{opcode.to_s(16)}"
    return opcode
end

#clearStatusRegisterOfMemoryObject



60
61
62
63
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 60

def clearStatusRegisterOfMemory
  #Clear Statut register
  write_command_Memory_WithoutMultiplexing(0x000000,0x50)
end

#connectObject

Connect board and get an instance to work with Return USB_STATE



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 31

def connect
  @device = @usb.devices(:idVendor => 0x0483, :idProduct => 0xFFFF)
  if @device.size == 0   then
      @device_version = ""
      return USB_STATE::NOT_CONNECTED
    else
    @dev = @device.first.open
      if RUBY_PLATFORM=~/linux/i && @dev.kernel_driver_active?(0)
        @dev.detach_kernel_driver(0)
      end
    @dev.claim_interface(0)
    Thread.abort_on_exception = true
    setStatutLed(USB_COMMAND::GREEN_LED,true);
    return USB_STATE::CONNECTED
  end
end

#consoleData(value) ⇒ Object



122
123
124
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 122

def consoleData(value)
  @callbackData.call(value)
end

#consoleInfo(value) ⇒ Object



128
129
130
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 128

def consoleInfo(value)
  @callbackInfo.call(value)
end

#consoleProgress(percent:, startTime:, endTime:) ⇒ Object



119
120
121
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 119

def consoleProgress(percent:,startTime:,endTime:)
  @callbackProgress.call(percent:percent,startTime:startTime,endTime:endTime)
end

#consoleSpeed(value) ⇒ Object



125
126
127
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 125

def consoleSpeed(value)
  @callbackSpeedOfTransfert.call(value)
end

#dumpFlash(path) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 63

def dumpFlash(path)
  resetSWD()
  #DUMP FLASH MEMORY TO A FILE
  @stm32.halt
  flash_size = (stm32.ahb.readWord(0x1ffff7e0) & 0xFFFF)
  puts "Flash size : #{(flash_size) } KB"
  puts "Dump flash"
  time = Time.new
  data = @stm32.flashRead(0x08000000,(flash_size*1024))
  time = Time.new - time
  puts "DUMP #{((data.size/time)).round(2)}Bytes/s #{(data.size)}Bytes in  #{time.round(4)} s"
  IO.binwrite(path, data.pack('C*'))
  puts "Finish dump"
end

#eraseBlockMemory(blockAddress) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 35

def eraseBlockMemory(blockAddress)
  #Read Five Word
  write_command_Memory_WithoutMultiplexing(blockAddress,0x0020)   #Block erase command
  statut = write_command_Memory_WithoutMultiplexing(blockAddress,0x00D0)   #Confirm Block erase command

   timeout = 10
  # while (statut != 128 ) && (timeout >= 0)
  #
  #  puts "#{statut}  #{timeout}"
  #    statut = readByteFromMemory(0) #read statut register
  #  sleep(100)
  #  if timeout == 0 then
  #    return statut
  #  else
  #    timeout = timeout-1
  #  end
  # end
  for ty in 0..4
    puts readByteFromMemory(0)
  end

  puts "Return timeout"
  return statut
end

#eraseFlashObject



58
59
60
61
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 58

def eraseFlash
  puts 'Erase'
  stm32.flashErase()
end

#getVersionNumberObject

Obtaint the version number of the board



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 75

def getVersionNumber
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::GET_VERSION_NUMBER)
  packet.push HardsploitAPI.highByte(USB_COMMAND::GET_VERSION_NUMBER)

  #remove header
  version_number = sendAndReceiveDATA(packet,1000).drop(4)
  if version_number.size < 20 then #if size more thant 20 char error when reading version number
      return version_number.pack('U*')
  else
    return "BAD VERSION NUMBER"
  end

end

#i2c_Generic_Dump(*args) ⇒ Object

  • startAddress

    Start address (included)

  • stopAddress

    Stop address (included)

  • sizeMax

    Size max of memory (important to calculate automaticly the number of byte to set address)



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/HardsploitAPI/HardsploitAPI_I2C.rb', line 98

def i2c_Generic_Dump (*args)
    parametters = HardsploitAPI.checkParametters(["speed","i2cBaseAddress","startAddress","stopAddress","sizeMax"],args)
    speed = parametters[:speed]
    i2cBaseAddress = parametters[:i2cBaseAddress]
    startAddress = parametters[:startAddress]
    stopAddress = parametters[:stopAddress]
    sizeMax = parametters[:sizeMax]

    if ((startAddress < 0)  or (startAddress > sizeMax-1)) then
      raise TypeError, "Start address can't be negative and not more than size max - 1"
    end
    if ((stopAddress < 0)  or (stopAddress > (sizeMax-1))) then
      raise TypeError, "Stop address can't be negative and not more than size max-1 because start at 0"
    end

    if (stopAddress <= startAddress) then
      raise TypeError, "Stop address need to be greater than start address"
    end

    numberOfByteAddress = (((Math.log(sizeMax-1,2)).floor + 1) / 8.0).ceil
    if numberOfByteAddress > 4 then
      raise TypeError, "Size max must be less than 2^32 about 4Gb"
    end

    if numberOfByteAddress <= 0 then
      raise TypeError, "There is an issue with calculating of number of byte needed"
    end
    startTime = Time.now
    packet_size = 2000 - numberOfByteAddress - 1
    number_complet_packet = ( (stopAddress-startAddress+1) / packet_size).floor
    size_last_packet =  (stopAddress-startAddress+1) % packet_size

    #SEND the first complete trame
    for i in 0..number_complet_packet-1 do
      packet = generate_i2c_read_command i2cBaseAddress,numberOfByteAddress+startAddress,i*packet_size,packet_size
      temp = i2c_Interact(speed,packet)
      case temp
        when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
          puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
        when HardsploitAPI::USB_STATE::ERROR_SEND
          puts "ERROR_SEND\n"
        when HardsploitAPI::USB_STATE::BUSY
          puts "BUSY"
        when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
          puts "TIMEOUT_RECEIVE\n"
        else
          #Remove header, result of read command and numberOfByte Address too
          consoleData ( process_dump_i2c_result( temp ) )
      end

      consoleProgress(percent:100*(i+1)/(number_complet_packet+ (size_last_packet.zero? ? 0 : 1)),startTime:startTime,endTime:Time.new)
    end

  if(size_last_packet > 0 )then
    packet = generate_i2c_read_command i2cBaseAddress,numberOfByteAddress,number_complet_packet*packet_size+startAddress,size_last_packet
    temp = i2c_Interact(speed,packet)
    case temp
      when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
        puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
      when HardsploitAPI::USB_STATE::ERROR_SEND
        puts "ERROR_SEND\n"
      when HardsploitAPI::USB_STATE::BUSY
        puts "BUSY"
      when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
        puts "TIMEOUT_RECEIVE\n"
      else
        #Remove header, result of read command and numberOfByte Address too
        consoleData ( process_dump_i2c_result ( temp ) )
     end
     consoleProgress(percent:100,startTime:startTime,endTime:Time.new)
  end

  delta = Time.now - startTime
  consoleSpeed "Write in #{delta.round(4)} sec"
end

#i2c_Generic_Import(*args) ⇒ Object

For the moment only with EEPROM (not need to erase or activate write)



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/HardsploitAPI/HardsploitAPI_I2C.rb', line 175

def i2c_Generic_Import (*args)
  parametters = HardsploitAPI.checkParametters(["speed","i2cBaseAddress","startAddress","pageSize","memorySize","dataFile","writePageLatency"],args)
  speed = parametters[:speed]
  i2cBaseAddress = parametters[:i2cBaseAddress]
  startAddress = parametters[:startAddress]
  pageSize = parametters[:pageSize]
  memorySize = parametters[:memorySize]
  dataFile = parametters[:dataFile]
  writePageLatency = parametters[:writePageLatency]

  startTime = Time.now
  begin
    file =  File.open(dataFile, 'rb')
    sizeFile = file.size
  rescue Exception => e
    raise Error::FileIssue, e.message
  end

  if ((startAddress < 0)  or (startAddress > memorySize-1)) then
    raise Error::WrongStartAddress
  end

  if ((pageSize <= 0) and (pageSize >1024)) then
    raise TypeError, "pageSize need to be greater than 0 and less than 1024"
  end

  numberOfByteAddress = (((Math.log(memorySize-1,2)).floor + 1) / 8.0).ceil
  if numberOfByteAddress > 4 then
    raise TypeError, "Size max must be less than 2^32 about 4Gb"
  end

  if numberOfByteAddress <= 0 then
    raise TypeError, "There is an issue with calculating of number of byte needed"
  end

  packet_size = pageSize
  number_complet_packet = (sizeFile / packet_size).floor
  size_last_packet =  sizeFile % packet_size

  #SEND the first complete trame
  for i in 0..number_complet_packet-1 do
    packet = generate_i2c_write_command i2cBaseAddress,numberOfByteAddress,i*packet_size,file.read(packet_size).unpack("C*")
    temp = i2c_Interact(speed,packet)
    case temp
      when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
        puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
      when HardsploitAPI::USB_STATE::ERROR_SEND
        puts "ERROR_SEND\n"
      when HardsploitAPI::USB_STATE::BUSY
        puts "BUSY"
      when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
        puts "TIMEOUT_RECEIVE\n"
      else
        #Remove header, result of read command and numberOfByte Address too
        process_import_i2c_result( temp )
    end

    consoleProgress(percent:100*(i+1)/(number_complet_packet+ (size_last_packet.zero? ? 0 : 1)),startTime:startTime,endTime:Time.new)

    #if too many error when write increase because we need to wait to write a full page
    sleep(writePageLatency)
  end

  if(size_last_packet > 0 )then
    packet = generate_i2c_write_command(i2cBaseAddress,numberOfByteAddress,number_complet_packet*packet_size+startAddress,file.read(size_last_packet).unpack("C*"))
    temp = i2c_Interact(speed,packet)
    case temp
      when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
        puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
      when HardsploitAPI::USB_STATE::ERROR_SEND
        puts "ERROR_SEND\n"
      when HardsploitAPI::USB_STATE::BUSY
        puts "BUSY"
      when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
        puts "TIMEOUT_RECEIVE\n"
      else
        #Remove header, result of read command and numberOfByte Address too
        process_import_i2c_result ( temp )
    end
      consoleProgress(percent:100,startTime:startTime,endTime:Time.new)
  end

  delta = Time.now - startTime
  consoleSpeed "Write in #{delta.round(4)} sec"
end

#i2c_Interact(*args) ⇒ Object

  • payload

    payload to send



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/HardsploitAPI/HardsploitAPI_I2C.rb', line 14

def i2c_Interact(*args)
  parametters = HardsploitAPI.checkParametters(["speed","payload"],args)
  speed = parametters[:speed]
  payload = parametters[:payload]

  if (speed < 0)  and (speed >3) then
    raise TypeError, 'Speed must be between 0 and 3'
  end

  if (payload.size > 4000) then
    raise TypeError, 'Size of the data need to be less than 4000'
  end

  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push speed #Add speed
  packet.concat payload #Add data

  sendPacket packet

  tmp= receiveDATA(2000)
  case tmp
    when HardsploitAPI::USB_STATE::BUSY
      return USB_STATE::BUSY
    when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
      return USB_STATE::TIMEOUT_RECEIVE
    else
      #remove header (4 bytes   2 for size 2 for type of command)
      return tmp.bytes.drop(4)
  end
end

#i2c_Scan(*args) ⇒ Object

  • Return An array 256 value for each addresse if 0 not present if 1 present



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/HardsploitAPI/HardsploitAPI_I2C.rb', line 55

def i2c_Scan(*args)
  parametters = HardsploitAPI.checkParametters(["speed"],args)
  speed = parametters[:speed]

  if (speed < 0)  and (speed >3) then
    raise TypeError, 'Speed must be between 0 and 3'
  end

  array_i2c_scan = Array.new
  result_scan = Array.new
  return_scan = Array.new

  #we want scan just read address it is a partial scan (fastest)
  for i in (1..255).step(2) do
    array_i2c_scan.push HardsploitAPI.lowByte(1)  #Count Low  Byte
    array_i2c_scan.push HardsploitAPI.highByte(1)   #Count High Byte
    array_i2c_scan.push i
  end

  result_scan = i2c_Interact(speed,array_i2c_scan)
  if result_scan.size != 256 then
    raise TypeError, "FPGA send a wrong I2C scan result, try again , check power jumper, fix wiring , power on ? (reboot the board if needed)"
  end

  for i in (0..result_scan.size-1).step(2) do
    #Check if ACK_ERROR
    if result_scan[i] == 1 then
      return_scan.push 1 #For write
      return_scan.push 1 #For read
    else
      return_scan.push 0 #For write
      return_scan.push 0 #For read
    end
  end
  return return_scan
end

#obtainCodesObject



24
25
26
27
28
29
30
31
32
33
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 24

def obtainCodes
  resetSWD()
  code = {
    :DebugPortId => debugPort.idcode(),
    :AccessPortId => stm32.ahb.idcode(),
    :CpuId => stm32.ahb.readWord(0xE000ED00),
    :DeviceId => stm32.ahb.readWord(0x1FFFF7E8)
  }
  return code
end

#read_Memory_WithoutMultiplexing(*args) ⇒ Object

Read parallele memory in asynchronous mode (blocking function) but callBack data is used to receive packet

  • addressStart

    32 bits address

  • addressStop

    32 bits address

  • bits8_or_bits16_DataSize

    0 for 8 bits operation & 1 for 16 bits operation

  • latency

    latency in ns range 7ns to 1600ns=1,6ms

Return USB_STATE End with TIMEOUT_RECEIVE but need to check if received the right number of bytes to ensure all is correct



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 152

def read_Memory_WithoutMultiplexing(*args)
parametters = HardsploitAPI.checkParametters(["addressStart","addressStop","bits8_or_bits16_DataSize","latency"],args)
  addressStart = parametters[:addressStart]
addressStop = parametters[:addressStop]
bits8_or_bits16_DataSize = parametters[:bits8_or_bits16_DataSize]
latency = parametters[:latency]


numberOfByteReaded = 0
packet = Array.new
packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

#Chek if 8bits or 16 bits
if bits8_or_bits16_DataSize == true then
  packet.push 1
else
  packet.push  0
end

#Check latency value
if ((latency >= 7)  and (latency <= 1600)) then
  packet.push (latency/6.66).floor
else
  raise TypeError, 'Latency value must be from 7 to 1695'
end

#Check address
if (addressStop <= addressStart  ) then
  raise TypeError, 'Stop address is less than start address'
end

packet.push  ((addressStart & 0xFF000000) >> 24 ) #AddStart3
packet.push  ((addressStart & 0x00FF0000) >> 16 ) #AddStart2
packet.push  ((addressStart & 0x0000FF00) >> 8 )  #AddStart1
packet.push  ((addressStart & 0x000000FF) >> 0)   #AddStart0

packet.push 0x10 #Memory read command
packet.push  ((addressStop & 0xFF000000) >> 24 ) #AddStart3
packet.push  ((addressStop & 0x00FF0000) >> 16 ) #AddStop2
packet.push  ((addressStop & 0x0000FF00) >> 8 )  #AddStop1
packet.push  ((addressStop & 0x000000FF) >> 0)   #AddStop0

sendPacket(packet)

if bits8_or_bits16_DataSize then
  sizeCalculated = (addressStop-addressStart+1)
else
  sizeCalculated = (addressStop-addressStart+1)*2
end

numberOfByteReaded = 0
while true
  tmp= receiveDATA(2000)
  case tmp
    when HardsploitAPI::USB_STATE::BUSY
      raise  "USB_STATE::BUSY"
    when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
      raise "Timeout"
    else
      #remove header (4 bytes   2 for size 2 for type of command)
      tmp = tmp.bytes.drop(4)
      numberOfByteReaded = numberOfByteReaded + tmp.size
      consoleData(tmp)

      puts "Receive #{numberOfByteReaded} of #{sizeCalculated}"
        if numberOfByteReaded >= sizeCalculated then
         #Exit because we received all data
         return
      end
    end
  end
end

#readBlockAP(size) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 156

def readBlockAP(size)
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push 0xAA #Read mode
  packet.push HardsploitAPI.lowByte(size)
  packet.push HardsploitAPI.highByte(size)

  result = sendAndReceiveDATA(packet,1000)
   if result.class == Array then
       if result.size >= 4   then #Receive read + 4bytes for header
         return result.drop(4)
      else
        raise "Receive just Header where is the data ? "
       end
   else # Receive and error
       raise "Error during reading  timeout or ACK issue "
   end
end

#readByteFromMemory(address) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 103

def readByteFromMemory(address)
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO


  #16 bits
  packet.push  0
  packet.push (1500/6.66).floor


  packet.push  ((address & 0xFF000000) >> 24 ) #AddStart3
  packet.push  ((address & 0x00FF0000) >> 16 ) #AddStart2
  packet.push  ((address & 0x0000FF00) >> 8 )  #AddStart1
  packet.push  ((address & 0x000000FF) >> 0)   #AddStart0

  packet.push 0x10 #Memory read command
  packet.push  ((address & 0xFF000000) >> 24 ) #AddStart3
  packet.push  ((address & 0x00FF0000) >> 16 ) #AddStop2
  packet.push  ((address & 0x0000FF00) >> 8 )  #AddStop1
  packet.push  ((address & 0x000000FF) >> 0)   #AddStop0

  result = sendAndReceiveDATA(packet,1000)

  if result == USB_STATE::TIMEOUT_RECEIVE then
    return "TIMEOUT"
  else
    if result.size == 6 then
        return HardsploitAPI.BytesToInt(result[4] , result[5])
    else
      raise "BAD RESPONSE"
    end
  end
end

#readDeviceIdMemoryObject



18
19
20
21
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 18

def readDeviceIdMemory
  write_command_Memory_WithoutMultiplexing(0x00000000,0x90) #ReadDeviceIdentifierCommand
  return readByteFromMemory(0)#Read  0
end

#readManufactuerCodeMemoryObject



13
14
15
16
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 13

def readManufactuerCodeMemory
  write_command_Memory_WithoutMultiplexing(0x00000000,0x90) #ReadDeviceIdentifierCommand
  return readByteFromMemory(1) #Read from 1 to 1 = read 1 byte at 1
end

#readModeObject



30
31
32
33
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 30

def readMode
  #go in read mode
  write_command_Memory_WithoutMultiplexing(0x000000,0x00FF)
end

#readSWD(ap, register) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 181

def readSWD(ap,register)
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push 0x11 #Read mode
  packet.push(calcOpcode(ap,register, true)) #Send Request

  result = sendAndReceiveDATA(packet,1000)
   if result.class == Array then
       if result.size == 4 + 4  then #Receive read + 4bytes for header
         convert = (result[7]  << 24)  + (result[6]  << 16) + (result[5]  << 8 ) + result[4]
         return convert
       elsif result.size == 4+1 then #receive ACK
        raise "Read error  ACK : #{result[4]}"
       else
         raise "Error during reading"
       end
   else # Receive and error
     raise "Error during reading  timeout "
   end
end

#receiveDATA(timeout) ⇒ Object

Wait to receive data

  • timeout

    timeout to read response (ms)

Return USB_STATE or array with response (improve soon with exception)



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 108

def receiveDATA(timeout)
  begin
    received_data =  dev.bulk_transfer(:endpoint=>IN_ENDPOINT, :dataIn=>USB::USB_TRAME_SIZE, :timeout=>timeout)
  rescue LIBUSB::ERROR_BUSY
    return USB_STATE::BUSY
  rescue LIBUSB::ERROR_TIMEOUT
    return USB_STATE::TIMEOUT_RECEIVE
  else
    return received_data
  end
end

#resetSWDObject

Return array with 1 byte for ACK Return 32bits integer for data read here is Core ID Raise if error



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 212

def resetSWD
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push 0x00 #Reset mode

  result = sendAndReceiveDATA(packet,1000)
  if result.class == Array then
      if result.size == 4 + 4  then #Receive read + 4bytes for header
        convert = (result[7]  << 24)  + (result[6]  << 16) + (result[5]  << 8 ) + result[4]
        return convert
      elsif result.size == 4 +1 then #reveice ACK
        raise "ERROR ACK #{result[4]}"
      else
        raise "Error during reading ICCODE result != 4"
      end
  else # Receive and error
    raise "Error during reading ICCODE timeout "
  end
end

#runSWDObject



15
16
17
18
19
20
21
22
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 15

def runSWD
  @debugPort = SWD_DEBUG_PORT.new(self)
  @stm32     = SWD_STM32.new(debugPort)

  resetSWD()
  #  Cortex M4 0x410FC241
  #  Cortex M3 0x411FC231
end

#sendAndReceiveDATA(packet_send, timeout) ⇒ Object

Send data and wait to receive response

  • packet_send

    array of byte

  • timeout

    timeout to read response (ms)

Return USB_STATE or array with response (improve soon with exception)



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 82

def sendAndReceiveDATA(packet_send,timeout)
  time = Time.new
  case sendPacket(packet_send)
    when USB_STATE::SUCCESSFUL_SEND
      received_data = receiveDATA(timeout)
      case received_data
        when USB_STATE::BUSY
          return  USB_STATE::BUSY
        when USB_STATE::TIMEOUT_RECEIVE
          return USB_STATE::TIMEOUT_RECEIVE
        else
          consoleSpeed "RECEIVE #{((received_data.bytes.to_a.size/(Time.new-time))).round(2)}Bytes/s  #{(received_data.bytes.to_a.size)}Bytes in  #{(Time.new-time).round(4)} s"
          return received_data.bytes.to_a
      end
    when USB_STATE::PACKET_IS_TOO_LARGE
      return  USB_STATE::PACKET_IS_TOO_LARGE
    when USB_STATE::ERROR_SEND
      return  USB_STATE::ERROR_SEND
    else
      return  USB_STATE::UNKNOWN_STATE
  end
end

#sendPacket(packet_send) ⇒ Object

Send USB packet

  • packet

    array with bytes

Return USB_STATE or array with response (improve soon with exception)



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 123

def sendPacket(packet_send)
  if packet_send.size <= 8191 then

    packet_send[0] = HardsploitAPI.lowByte(packet_send.size)
    packet_send[1] = HardsploitAPI.highByte(packet_send.size)

    #if a multiple of packet size add a value to explicit the end of trame
    if packet_send.size % 64 ==0 then
      packet_send.push 0
    end

    number_of_data_send = 0
    time = Benchmark.realtime  do
      number_of_data_send =  @dev.bulk_transfer(:endpoint=>OUT_ENDPOINT, :dataOut=>packet_send.pack('c*'),:timeout=>3000)
    end
    consoleSpeed "SEND #{((number_of_data_send/time)).round(2)}Bytes/s  SEND #{(number_of_data_send)}Bytes in  #{time.round(4)} s"
    if number_of_data_send ==  packet_send.size then
      return USB_STATE::SUCCESSFUL_SEND
    else
      return USB_STATE::ERROR_SEND
    end
  else
    return USB_STATE::PACKET_IS_TOO_LARGE
  end
end

#setStatutLed(*args) ⇒ Object

Set the leds of uC returning nothing

  • led

    USB_COMMAND::GREEN_LED or USB_COMMAND::RED_LED

  • state

    callback to return data for dump function



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/HardsploitAPI/HardsploitAPI_USB_COMMUNICATION.rb', line 15

def setStatutLed(*args)
  parametters = HardsploitAPI.checkParametters(["led","state"],args)
  led = parametters[:led]
  state = parametters[:state]

  packet_send = Array.new
  packet_send.push 0 #size set before send automatic
  packet_send.push 0 #size set before send automatic
  packet_send.push HardsploitAPI.lowByte(led)
  packet_send.push HardsploitAPI.highByte(led)
  packet_send.push (state ? 1 : 0)
  return sendPacket(packet_send)
end

#setWiringLeds(*args) ⇒ Object

  • value

    64 bits (8x8 Bytes) values to represent led (PortH PortG PortF PortE PortD PortC PortB PortA)



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/HardsploitAPI/HardsploitAPI.rb', line 50

def setWiringLeds(*args)
  parametters = HardsploitAPI.checkParametters(["value"],args)
  val = parametters[:value]

  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  packet.push 0x23 #Command SPI write wiring led

  packet.push  HardsploitAPI.reverseBit((val & 0x00000000000000FF) >> 0)
  packet.push  HardsploitAPI.reverseBit((val & 0x000000000000FF00) >> 8 )
  packet.push  HardsploitAPI.reverseBit((val & 0x0000000000FF0000) >> 16 )
  packet.push  HardsploitAPI.reverseBit((val & 0x00000000FF000000) >> 24 )
  packet.push  HardsploitAPI.reverseBit((val & 0x000000FF00000000) >> 32 )
  packet.push  HardsploitAPI.reverseBit((val & 0x0000FF0000000000) >> 40 )
  packet.push  HardsploitAPI.reverseBit((val & 0x00FF000000000000) >> 48 )
  packet.push  HardsploitAPI.reverseBit((val & 0xFF00000000000000) >> 56 )

  return  self.sendPacket(packet)
end

#signalHelpingWiring(*args) ⇒ Object

Power on the led for each signal specified Params:

signal

Name of signal you want visual help (set the led)



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/HardsploitAPI/HardsploitAPI_CONSTANT.rb', line 15

def signalHelpingWiring(*args)
  parametters = HardsploitAPI.checkParametters(["signal"],args)
  signal = parametters[:signal]

  wires = Hash.new

  #Parallel module
  wires["A0"] = 0
  wires["A1"] = 1
  wires["A2"] = 2
  wires["A3"] = 3
  wires["A4"] = 4
  wires["A5"] = 5
  wires["A6"] = 6
  wires["A7"] = 7
  wires["A8"] = 8
  wires["A9"] = 9
  wires["A10"] = 10
  wires["A11"] = 11
  wires["A12"] = 12
  wires["A13"] = 13
  wires["A14"] = 14
  wires["A15"] = 15
  wires["A16"] = 16
  wires["A17"] = 17
  wires["A18"] = 18
  wires["A19"] = 19
  wires["A20"] = 20
  wires["A21"] = 21
  wires["A22"] = 22
  wires["A23"] = 23
  wires["A24"] = 24
  wires["A25"] = 25
  wires["A26"] = 26
  wires["A27"] = 27
  wires["A28"] = 28
  wires["A29"] = 29
  wires["A30"] = 30
  wires["A31"] = 31

  wires["D0"] = 32
  wires["D1"] = 33
  wires["D2"] = 34
  wires["D3"] = 35
  wires["D4"] = 36
  wires["D5"] = 37
  wires["D6"] = 38
  wires["D7"] = 39
  wires["D8"] = 40
  wires["D9"] = 41
  wires["D10"] = 42
  wires["D11"] = 43
  wires["D12"] = 44
  wires["D13"] = 45
  wires["D14"] = 46
  wires["D15"] = 47

  wires["RST"] = 48
  wires["CE"] = 49
  wires["OE"] = 50
  wires["WE"] = 51
  wires["CLK"] = 52
  wires["WP"] = 53
  wires["ADV"] = 54


  #SPI module
  wires["CS"] = 0
  wires["SPI_CLK"] = 1
  wires["MOSI"] = 2
  wires["MISO"] = 3

  #I2C module
  wires["I2C_CLK"] = 0
  wires["SDA"] = 1

  begin
    setWiringLeds(2**wires[signal])
  rescue Exception => e
     raise 'UNKNOWN SIGNAL'
  end
end

#spi_Generic_Dump(*args) ⇒ Object

Spi generic dump

  • mode

    SPI mode 0,1,2,3

  • speed

    Range 1-255 SPI clock = 150Mhz / (2*speed) tested from 3 to 255 (25Mhz to about 0.3Khz)

  • readSpiCommand

    The read command

  • startAddress

    Start address (included)

  • stopAddress

    Stop address (included)

  • sizeMax

    Size max of memory (important to calculate automaticly the number of byte to set address)



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/HardsploitAPI/HardsploitAPI_SPI.rb', line 208

def spi_Generic_Dump (*args)
    parametters = HardsploitAPI.checkParametters(["mode","speed","readSpiCommand","startAddress","stopAddress","sizeMax"],args)
    mode = parametters[:mode]
    speed = parametters[:speed]
    readSpiCommand = parametters[:readSpiCommand]
    startAddress = parametters[:startAddress]
    stopAddress = parametters[:stopAddress]
    sizeMax = parametters[:sizeMax]


    if (mode < 0)  and (mode >3) then
      raise TypeError, 'Mode must be between 0 and 3'
    end
    if (speed <= 2)  and (speed >256) then
      raise TypeError, 'Speed must be between 3 and 255'
    end

    if ((startAddress < 0)  or (startAddress > sizeMax-1)) then
      raise TypeError, "Start address can't be negative and not more than size max - 1"
    end
    if ((stopAddress < 0)  or (stopAddress > (sizeMax-1))) then
      raise TypeError, "Stop address can't be negative and not more than size max-1 because start at 0"
    end

    if (stopAddress < startAddress) then
      raise TypeError, "Stop address need to be greater than start address"
    end

    numberOfByteAddress = (((Math.log(sizeMax-1,2)).floor + 1) / 8.0).ceil
    if numberOfByteAddress > 4 then
      raise TypeError, "Size max must be less than 2^32 about 4Gb"
    end

    if numberOfByteAddress <= 0 then
      raise TypeError, "There is an issue with calculating of number of byte needed"
    end

    #Start time
    startTime = Time.now
    packet_size = 4000 - numberOfByteAddress - 1
    number_complet_packet = ( (stopAddress-startAddress+1) / packet_size).floor
    size_last_packet =  (stopAddress-startAddress+1) % packet_size

    #SEND the first complete trame
    for i in 0..number_complet_packet-1 do
      packet = generate_spi_read_command numberOfByteAddress,readSpiCommand,i*packet_size+startAddress,packet_size
      temp = spi_Interact(mode,speed,packet)
      case temp
        when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
          puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
        when HardsploitAPI::USB_STATE::ERROR_SEND
          puts "ERROR_SEND\n"
        when HardsploitAPI::USB_STATE::BUSY
          puts "BUSY"
        when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
          puts "TIMEOUT_RECEIVE\n"
        else
          #Remove header, result of read command and numberOfByte Address too
          #puts "receive real size #{temp.size}"
          consoleData temp.drop(numberOfByteAddress+1)
      end
      consoleProgress(percent:100*(i+1)/(number_complet_packet+ (size_last_packet.zero? ? 0 : 1)),startTime:startTime,endTime:Time.new)
    end

  if(size_last_packet > 0 )then
      packet = generate_spi_read_command numberOfByteAddress,readSpiCommand,number_complet_packet*packet_size+startAddress,size_last_packet
      temp = spi_Interact(mode,speed,packet)
      case temp
        when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
          puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
        when HardsploitAPI::USB_STATE::ERROR_SEND
          puts "ERROR_SEND\n"
        when HardsploitAPI::USB_STATE::BUSY
          puts "BUSY"
        when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
          puts "TIMEOUT_RECEIVE\n"
        else
          #Remove header, result of read command and numberOfByte Address too
          #puts "receive real size #{temp.size}"
          consoleData temp.drop(numberOfByteAddress+1)
          consoleProgress(percent:100,startTime:startTime,endTime:Time.now)
        end
    end
    delta = Time.now - startTime
    consoleSpeed "Write in #{delta.round(4)} sec"
end

#spi_Generic_Import(*args) ⇒ Object

Spi generic Import

  • mode

    SPI mode 0,1,2,3

  • speed

    Range 1-255 SPI clock = 150Mhz / (2*speed) tested from 3 to 255 (25Mhz to about 0.3Khz)

  • writeSpiCommand

    The write command

  • startAddress

    Start address (included)

  • pageSize

    Size of page

  • memorySize

    Size max of memory in byte (important, to calculate automatically the number of byte to set address)

  • saveFile

    File contain data

  • writePageLatency

    Time to wait after each pages written

  • enableWriteSpiCommand

    Enable write commad

  • clearSpiCommand

    Bulk erase command

  • clearChipTime

    Time to erase entire the memory (bulk erase) in case of flash memory, 240 seconds for a 512Mb spansion memory and 13 seconds for a 16Mb Micron memory, see the datasheet

  • isFLASH

    True if it is a Flash memory (add clear content)



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/HardsploitAPI/HardsploitAPI_SPI.rb', line 74

def spi_Generic_Import (*args)
    parametters = HardsploitAPI.checkParametters(["mode","speed","startAddress","pageSize","memorySize","dataFile","writeSpiCommand","writePageLatency","enableWriteSpiCommand","clearSpiCommand","clearChipTime","isFLASH"],args)
    mode = parametters[:mode]
    speed = parametters[:speed]
    startAddress = parametters[:startAddress]
    pageSize = parametters[:pageSize]
    memorySize = parametters[:memorySize]
    dataFile = parametters[:dataFile]
    writePageLatency = parametters[:writePageLatency]

    #most of the time 0x02
    writeSpiCommand = parametters[:writeSpiCommand]
    writeSpiCommand
    #most of the time 0x06
    enableWriteSpiCommand = parametters[:enableWriteSpiCommand]

    #most of the time 0x60  chip eraseTime
    clearSpiCommand = parametters[:clearWriteSpiCommand]

    # in second
    clearChipTime = parametters[:clearChipTime]

    #if flash memory
    isFLASH = parametters[:isEEPROM]

    #Start time
    startTime = Time.now
    begin
      file = File.open(dataFile, 'rb')
      sizeFile = file.size
    rescue Exception => e
      raise Error::FileIssue, e.message
    end

    if (mode < 0)  and (mode >3) then
      raise TypeError, 'Mode must be between 0 and 3'
    end
    if (speed <= 2)  and (speed >256) then
      raise TypeError, 'Speed must be between 3 and 255'
    end

    if ((startAddress < 0)  or (startAddress > memorySize-1)) then
      raise Error::WrongStartAddress
    end

    if ((pageSize <= 0) and (pageSize >2048)) then
      raise TypeError, "pageSize need to be greater than 0 and less than 2048"
    end

    numberOfByteAddress = (((Math.log(memorySize-1,2)).floor + 1) / 8.0).ceil
    if numberOfByteAddress > 4 then
      raise TypeError, "Size max must be less than 2^32 about 4Gb"
    end

    if numberOfByteAddress <= 0 then
      raise TypeError, "There is an issue with calculating of number of byte needed"
    end

    #if flash memory we need to erase it before and wait enought
    #time (erase cycle time in datasheet) or polling status register
    if isFLASH then
      spi_Interact(mode:mode,speed:speed,payload:[clearSpiCommand])
      sleep(clearChipTime)
    end

    startTime = Time.now
    packet_size = pageSize
    number_complet_packet = (sizeFile / packet_size).floor
    size_last_packet =  sizeFile % packet_size

    #SEND the first complete trame
    for i in 0..number_complet_packet-1 do
      #Enable write latch
      spi_Interact(mode:mode,speed:speed,payload:[enableWriteSpiCommand])
      packet = generate_spi_write_command numberOfByteAddress,writeSpiCommand,i*packet_size+startAddress,file.read(packet_size).unpack("C*")
      temp = spi_Interact(mode,speed,packet)
      case temp
        when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
          puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
        when HardsploitAPI::USB_STATE::ERROR_SEND
          puts "ERROR_SEND\n"
        when HardsploitAPI::USB_STATE::BUSY
          puts "BUSY"
        when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
          puts "TIMEOUT_RECEIVE\n"
        else
          #Remove header, result of read command and numberOfByte Address too
          #consoleData temp.drop(numberOfByteAddress+1)
          if packet.size != packet.size then
            raise HardsploitAPI::SpiError
          end
      end

      consoleProgress(percent:100*(i+1)/(number_complet_packet+ (size_last_packet.zero? ? 0 : 1)),startTime:startTime,endTime:Time.new)
      #if too many error when write increase because we need to wait to write a full page
      sleep(writePageLatency)
    end

    if(size_last_packet > 0 )then
      #Enable write latch
      spi_Interact(mode:mode,speed:speed,payload:[enableWriteSpiCommand])
      packet = generate_spi_write_command numberOfByteAddress,writeSpiCommand,number_complet_packet*packet_size+startAddress,file.read(size_last_packet).unpack("C*")
      temp = spi_Interact(mode,speed,packet)
      case temp
        when HardsploitAPI::USB_STATE::PACKET_IS_TOO_LARGE
          puts "PACKET_IS_TOO_LARGE max: #{HardsploitAPI::USB::USB_TRAME_SIZE}"
        when HardsploitAPI::USB_STATE::ERROR_SEND
          puts "ERROR_SEND\n"
        when HardsploitAPI::USB_STATE::BUSY
          puts "BUSY"
        when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
          puts "TIMEOUT_RECEIVE\n"
        else
          #Remove header, result of write command and numberOfByte Address too
          #consoleData temp.drop(numberOfByteAddress+1)
          if packet.size != packet.size then
            raise HardsploitAPI::SpiError
          end
      end
      #Send 100% in case of last packet
      consoleProgress(percent:100,startTime:startTime,endTime:Time.now)
    end
    delta = Time.now - startTime
    consoleSpeed "Write in #{delta.round(4)} sec"
end

#spi_Interact(*args) ⇒ Object

SPI interact

  • mode

    SPI mode 0,1,2,3

  • speed

    Range 1-255 SPI clock = 150Mhz / (2*speed) tested from 3 to 255 (25Mhz to about 0.3Khz)

  • payload

    Byte array want to send

  • Return SPI data received



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/HardsploitAPI/HardsploitAPI_SPI.rb', line 17

def spi_Interact(*args)
  parametters = HardsploitAPI.checkParametters(["mode","speed","payload"],args)
  mode = parametters[:mode]
  speed = parametters[:speed]
  payload = parametters[:payload]

  if (mode < 0)  and (mode >3) then
    raise TypeError, 'Mode must be between 0 and 3'
  end
  if (speed <= 2)  and (speed >256) then
    raise TypeError, 'Speed must be between 3 and 255'
  end

  if (payload.size > 4000) then
    raise TypeError, 'Size of the data need to be less than 4000'
  end

  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push mode #Add mode
  packet.push speed #Add speed
  packet.concat payload #Add data

  sendPacket packet

  tmp= receiveDATA(1000)
  case tmp
    when HardsploitAPI::USB_STATE::BUSY
      return USB_STATE::BUSY
    when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
      return USB_STATE::TIMEOUT_RECEIVE
    else
      #remove header (4 bytes   2 for size 2 for type of command)
      return tmp.bytes.drop(4)
  end
end

#startFPGAObject



34
35
36
37
38
39
40
41
# File 'lib/HardsploitAPI/HardsploitAPI_FIRMWARE.rb', line 34

def startFPGA
  packet = Array.new
  packet.push HardsploitAPI.lowByte(4)
  packet.push HardsploitAPI.highByte(4)
  packet.push HardsploitAPI.lowByte(USB_COMMAND::START_FPGA)
  packet.push HardsploitAPI.highByte(USB_COMMAND::START_FPGA)
  self.sendPacket(packet)
end

#stopFPGAObject



42
43
44
45
46
47
48
49
# File 'lib/HardsploitAPI/HardsploitAPI_FIRMWARE.rb', line 42

def stopFPGA
  packet = Array.new
  packet.push HardsploitAPI.lowByte(4)
  packet.push HardsploitAPI.highByte(4)
  packet.push HardsploitAPI.lowByte(USB_COMMAND::STOP_FPGA)
  packet.push HardsploitAPI.highByte(USB_COMMAND::STOP_FPGA)
  self.sendPacket(packet)
end

#test_InteractReadObject

return [Integer] 64bits



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/HardsploitAPI/HardsploitAPI_TEST_INTERACT.rb', line 60

def test_InteractRead
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  ##packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO
  packet.push 0x50

  #Read mode
  packet.push 0xCD

 packet.push 0xA1
 packet.push 0xA2
 packet.push 0xA3
 packet.push 0xA4
 packet.push 0xA5
 packet.push 0xA6
 packet.push 0xA7
   packet.push 0xA8


  sendPacket packet

  tmp= receiveDATA(1000)
  case tmp
    when HardsploitAPI::USB_STATE::BUSY
      return USB_STATE::BUSY
    when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
      puts "TIMEOUT"
    # raise "test_InteractRead Timeout"
    else
      #remove header (4 bytes   2 for size 2 for type of command)
      tmp = tmp.bytes.drop(4)
      return  0 |  (tmp[0] << 0) |  (tmp[1] << 8)   |  (tmp[2] << 16)  |  (tmp[3] << 24) |  (tmp[4] << 32) |  (tmp[5] << 40)  |  (tmp[6] << 48)  | (tmp[7] << 56)
  end
end

#test_InteractWrite(*args) ⇒ Object

Write value of 64 IO for testing purpose

  • value

    64bits to write on all ports

return [Integer] Return the value sent (lookback) (64bits)



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/HardsploitAPI/HardsploitAPI_TEST_INTERACT.rb', line 15

def test_InteractWrite(*args)
  parametters = HardsploitAPI.checkParametters(["value"],args)
  val = parametters[:value]

  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  #Command RAW COMMUNICATION TO FPGA FIFO
  packet.push 0x50

  #Write mode
  packet.push 0xEF

  packet.push  ((val & 0x00000000000000FF) >> 0)
  packet.push  ((val & 0x000000000000FF00) >> 8 )
  packet.push  ((val & 0x0000000000FF0000) >> 16 )
  packet.push  ((val & 0x00000000FF000000) >> 24 )
  packet.push  ((val & 0x000000FF00000000) >> 32 )
  packet.push  ((val & 0x0000FF0000000000) >> 40 )
  packet.push  ((val & 0x00FF000000000000) >> 48 )
  packet.push  ((val & 0xFF00000000000000) >> 56 )

  sendPacket packet

  tmp= receiveDATA(1000)
  case tmp
    when HardsploitAPI::USB_STATE::BUSY
      return USB_STATE::BUSY
    when HardsploitAPI::USB_STATE::TIMEOUT_RECEIVE
      return USB_STATE::TIMEOUT_RECEIVE
    else
      #remove header (4 bytes   2 for size 2 for type of command)
      tmp = tmp.bytes.drop(4)

      return  0 |  (tmp[0] << 0) |  (tmp[1] << 8)   |  (tmp[2] << 16)  |  (tmp[3] << 24) |  (tmp[4] << 32) |  (tmp[5] << 40)  |  (tmp[6] << 48)  | (tmp[7] << 56)
  end
end

#unlockBlock(blockAddress) ⇒ Object



65
66
67
68
69
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 65

def unlockBlock (blockAddress)
  write_command_Memory_WithoutMultiplexing(blockAddress,0x0060) #Lock Block Command
  write_command_Memory_WithoutMultiplexing(blockAddress,0x00D0) #UnLock  Command
  return readByteFromMemory(0x000000) #read statut register
end

#uploadFirmware(*args) ⇒ Object

Wait to receive data

  • pathFirmware

    path of rpd file (vhdl)

  • checkFirmware

    boolean if check is needed (recommended false, in case issue true to check)

Return true if firmware write == firmware read (slow because read the firmware for check)



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/HardsploitAPI/HardsploitAPI_FIRMWARE.rb', line 16

def uploadFirmware(*args)
  parametters = HardsploitAPI.checkParametters(["pathFirmware","checkFirmware"],args)
  pathFirmware = parametters[:pathFirmware]
  checkFirmware = parametters[:checkFirmware]

  stopFPGA
  eraseFirmware
  firmwarewrite = self.writeFirmware(pathFirmware)#return array of bytes write
  if checkFirmware == true then
    firmwareRead = self.readFirmware(firmwarewrite.length) #return array of bytes read
    startFPGA
    return (firmwarewrite == firmwareRead)
  else
    startFPGA
    return true
  end
end

#write_command_Memory_WithoutMultiplexing(address, data) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 71

def write_command_Memory_WithoutMultiplexing(address,data)
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push  0 #16 bits
  packet.push (1500/6.66).floor  #latency at 1500ns

  packet.push  ((address & 0xFF000000) >> 24 ) #AddStart3
  packet.push  ((address & 0x00FF0000) >> 16 ) #AddStart2
  packet.push  ((address & 0x0000FF00) >> 8 )  #AddStart1
  packet.push  ((address & 0x000000FF) >> 0)   #AddStart0
  packet.push 0x20 #Memory write command
  packet.push  ((data & 0xFF00) >> 8 )  #Data HIGHT BYTE
  packet.push  ((data & 0xFF) >> 0)  #Data LOW BYTE


  result = sendAndReceiveDATA(packet,1000)
   if result == USB_STATE::TIMEOUT_RECEIVE then
     raise "TIMEOUT"
  elsif result[4] == (data & 0xFF)

     return readByteFromMemory(0)
  else
     raise "ERROR BAD RESPONSE"
   end
end

#writeBlockAP(data) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 119

def writeBlockAP(data)
  if data.size > 8000 then
    raise "data is too big > 8000"
  end

  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO
  packet.push 0xBB #Write ap
  packet.push *data

  result = sendAndReceiveDATA(packet,1000)
  if result.class == Array then
      if result.size == 1 + 4 then #receive ACK
        if result[4] == 1 then
            return true
        elsif result[4] == 2 then
            raise "WAIT response"
        elsif result[4] == 4 then
            raise "FAULT response"
        else
            raise "WRITE ERROR #{result[4]}"
        end
      else
        raise "Error during writing"
      end
  else # Receive and error
    raise "Error during writing, timeout "
  end
    return false
end

#writeByteToMemory(address, value) ⇒ Object



23
24
25
26
27
28
# File 'lib/HardsploitAPI/HardsploitAPI_NO_MUX_PARALLELE_MEMORY.rb', line 23

def writeByteToMemory(address,value)
  #Write data in word mode  and read Five status register
  write_command_Memory_WithoutMultiplexing(address,0x0040)
  write_command_Memory_WithoutMultiplexing(address,value)
  return readByteFromMemory(0)
end

#writeFlash(path) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 36

def writeFlash(path)
  resetSWD()
  dataWrite = IO.binread(path)
  dataWrite = dataWrite.unpack("C*")
  puts "Halting Processor"
  stm32.halt()
  puts "Erasing Flash"
  stm32.flashUnlock()
  stm32.flashErase()
  puts "Programming Flash"
  stm32.flashProgram()
  time = Time.new
  stm32.flashWrite(0x08000000, dataWrite)
  time = Time.new - time
  puts "Write #{((dataWrite.size/time)).round(2)}Bytes/s #{(dataWrite.size)}Bytes in  #{time.round(4)} s"
  stm32.flashProgramEnd()
  puts "Resetting"
  stm32.sysReset()
  puts "Start"
  stm32.unhalt
end

#writeSWD(ap, register, data) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/HardsploitAPI/SWD/HardsploitAPI_SWD.rb', line 78

def writeSWD(ap,register,data)
  packet = Array.new
  packet.push 0  #low byte of lenght of trame refresh automaticly before send by usb
  packet.push 0  #high byte of lenght of trame refresh automaticly before send by usb
  packet.push HardsploitAPI.lowByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)
  packet.push HardsploitAPI.highByte(HardsploitAPI::USB_COMMAND::FPGA_COMMAND)

  packet.push 0x50 #Command RAW COMMUNICATION TO FPGA FIFO

  packet.push 0x10 #Write mode

  packet.push (calcOpcode(ap, register, false)) #Send Request

  packet.push  ((data & 0xFF) >> 0)
  packet.push  ((data & 0xFF00) >> 8 )
  packet.push  ((data & 0xFF0000) >> 16 )
  packet.push  ((data & 0xFF000000) >> 24 )

  result = sendAndReceiveDATA(packet,1000)

  if result.class == Array then
      if result.size == 1 + 4 then #receive ACK
        if result[4] == 1 then
            return true
        elsif result[4] == 2 then
            raise "WAIT response"
        elsif result[4] == 4 then
            raise "FAULT response"
        else
            raise "WRITE ERROR #{result[4]}"
        end
      else
        raise "Error during writing}"
      end
  else # Receive and error
    raise "Error during writing, timeout "
  end

  return false
end