Skip to content

Instantly share code, notes, and snippets.

@jamesduncombe
Created July 1, 2014 20:47
Show Gist options
  • Save jamesduncombe/b4732a4ffee6a8561dc0 to your computer and use it in GitHub Desktop.
Save jamesduncombe/b4732a4ffee6a8561dc0 to your computer and use it in GitHub Desktop.
JPEG Smash but in Ruby...
#!/usr/bin/env ruby
require 'optparse'
options = {}
# Markers
JPEG_START = 'ffda'
JPEG_END = 'ffd9'
OptionParser.new do |opts|
opts.banner = 'Usage: jpeg_crush.rb [options]'
opts.on('-f', '--file [FILE]', 'Use source file') do |v|
options[:file] = v
end
opts.on('-o', '--output-file [FILE]', 'Use output file') do |v|
options[:output_file] = v
end
opts.on('-m', '--message [MESSAGE]', 'Specify message to inject') do |v|
options[:message] = v.unpack("H*").first.scan(/.{2}/)
end
end.parse!
puts 'Opening source file...'
if File.exists? options[:file]
original = File.binread(options[:file])
else
raise ArgumentError, 'Incorrect filename given'
end
puts 'Unpacking hex into pairs...'
ready = original.unpack('H*').first.scan(/.{2}/) # get hex pairs
def start_of_data(data)
data.each_with_index { |e,i| return i if e == 'ff' && data[i+1] == 'da' }
end
def end_of_data(data)
data.each_with_index { |e,i| return i if e == 'ff' && data[i+1] == 'd9' }
end
# remember these are split into 2's and there's 4 as delimeters (ffda and ffd9) hance
# the 2 offset forwards and back (we don't want to ovewrite the markers)
puts 'Getting offsets for JPEG markers...'
starts = start_of_data(ready) + 2
ends = end_of_data(ready) - 2
puts 'Get the length of my name, insert Hex randomly...'
options[:message].count.times do |t|
loc = rand(starts+2..ends-2)
ready[loc] = options[:message].shuffle.first
end
# re-assemble file for writing out to a JPEG file
ready = [ready.join].pack('H*')
f = File.open(options[:output_file], 'w+')
f.write ready
f.close
puts 'Done :)'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment