#!/usr/bin/ruby require "optparse" require 'openssl' require 'zip' # zip require 'zip/filesystem' # rubyzip require 'rubygems' require 'json' require 'pp' require 'digest/md5' require 'archive/zip' """ checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.3.0/android.zip core.android.default.apk md5=03e90c8c603c42977e706c681fc5a755 core.android.default.v2.apk md5=cf4a89c9f85cf7bfda10fa6117a6b72f core.android.default.melt.apk md5=e449374d8cf5caa80692ce5a22d735d7 checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.2.0/android.zip core.android.default.apk md5=c0870d801b03caaa0292754f3b2c2044 core.android.default.v2.apk md5=315ae1c6d2e34dceb944f0f2ebdd9cf5 core.android.default.melt.apk md5=720ecb0f5fbee65f91cbd62559b142fb checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.2.1/android.zip core.android.default.apk md5=6e894a1ddb7aed7e398add92aa5e563e core.android.default.v2.apk md5=e2f7cce9405a56eb8c8694eb9e195f15 core.android.default.melt.apk md5=920336ed845548b9dfe0d3649ddeb0de checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.0.0/android.zip core.android.default.apk md5=c7ccdefad7c154a8d0a1e0f53d49316b core.android.default.v2.apk md5=bc427eeb26a706195772ba41825bfc9e core.android.default.melt.apk md5=7794a39bc2220cca4ad119035edf142d checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.1.0/android.zip core.android.default.apk md5=7c9b98d2027a8a4b628d431c58c70967 core.android.default.v2.apk md5=22acb333af193441db0bb24153650e50 core.android.default.melt.apk md5=ed2c161b8da6761f5b87add74836895b checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.1.5/android.zip core.android.default.apk md5=ecf914bcd533fb23570982d3fc5449e7 core.android.default.v2.apk md5=e31327e8e5db9db308599a21249458e3 core.android.default.melt.apk md5=0458f92001d48f192fb26cc9db4a44b7 checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//8.4.1/android.zip core.android.default.apk md5=8b6ff935d4c7e12a1a7458e4994e4778 core.android.default.v2.apk md5=a413f01503427b6f226a13b2e8799d91 core.android.default.melt.apk md5=56510f977ac7eede8cf481a5ff1c65db checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.2.3/android.zip core.android.default.apk md5=a3d065c92de286c1ef40cb1f282da65c core.android.default.v2.apk md5=36fd79e15448fd1a332db9a415690d49 core.android.default.melt.apk md5=9c5302c8ec2cbe1cf62c78d904f78132 checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//9.1.1/android.zip core.android.default.apk md5=ecf914bcd533fb23570982d3fc5449e7 core.android.default.v2.apk md5=e31327e8e5db9db308599a21249458e3 core.android.default.melt.apk md5=0458f92001d48f192fb26cc9db4a44b7 checking /Volumes/SHARE/RELEASE/SVILUPPO/previous cores//8.4.0/android.zip core.android.default.apk md5=8b6ff935d4c7e12a1a7458e4994e4778 core.android.default.v2.apk md5=a413f01503427b6f226a13b2e8799d91 core.android.default.melt.apk md5=56510f977ac7eede8cf481a5ff1c65db """ def aes_decrypt(enc_text, key, padding = 1) decipher = OpenSSL::Cipher.new('AES-128-CBC') decipher.decrypt decipher.padding = padding decipher.key = key decipher.iv = "\x00" * decipher.iv_len data = decipher.update(enc_text) data << decipher.final return data end def analyze_android(file, dir, pwd) conf = "" core = "" digest = "" if not (pwd.nil? or pwd[0].nil?) tmp_file = "_"+file Archive::Zip.extract(file, tmp_file, :password => pwd) Dir[tmp_file+"/*"].select do |e| if File.file?(e) puts "found file #{e}" file = e break; end end end Zip::File.open(file) do |z| conf = z.file.open('assets/c.bin', "rb") { |f| f.read } core = z.file.open('assets/r.bin', "rb") { |f| f.read } digest = z.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} end ident = 'RCS_' + core[4..13] water = core[150..157] key = core[46...(46+16)] # key = core[46...78] conf = aes_decrypt(conf, key) conf = conf[0...-20] json = JSON.parse(conf) actions = json['actions'] sync = nil actions.each do |action| action['subactions'].each do |sub| if action['desc'].eql?("SYNC") sync = sub['host'] end end end if !actions.nil? puts "WATERMARK: #{water}" puts 'IDENT: ' + ident puts 'SYNC ADDRESS: ' + (sync ? sync : 'failed to retrieve') puts 'MD5 digest: ' + digest File.open("./c.conf","w+") {|r| r.write(json.pretty_inspect)} if !dir.nil? Dir.glob(dir+'/**/android.zip') do |f| puts "checking "+f Zip::File.open(f) do |z| tmp = z.file.open('core.android.default.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} if(digest.eql?digestTmp) puts "found in " +f+ " core.android.default.apk md5="+digestTmp+"MATCH!" return; end end tmp = z.file.open('core.android.v2.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} if(digest.eql?digestTmp) puts "found in " +f+ " core.android.v2.apk md5="+digestTmp+"MATCH!" return; end end tmp = z.file.open('core.android.melt.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} if(digest.eql?digestTmp) puts "found in " +f+ " core.android.melt.apk md5="+digestTmp+"MATCH!" return; end end end # core.android.default.apk core.android.melt.apk core.android.v2.apk end end end def check_md5(f, file, digest) puts "checking "+f Zip::File.open(f) do |z| tmp = z.file.open('core.android.default.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} puts " core.android.default.apk md5="+digestTmp if(digest.eql?digestTmp) puts "found in " +f+ " core.android.default.apk md5="+digestTmp+"MATCH!" return; end end tmp = z.file.open('core.android.v2.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} puts " core.android.default.v2.apk md5="+digestTmp if(digest.eql?digestTmp) puts "found in " +f+ " core.android.v2.apk md5="+digestTmp+"MATCH!" return; end end tmp = z.file.open('core.android.melt.apk', "rb") { |f| f.read } File.delete("./tmp.conf") if File.exist?("./tmp.conf") File.binwrite("./tmp.conf",tmp,0) Zip::File.open("./tmp.conf") do |zz| digestTmp = zz.file.open('classes.dex', "rb") { |f| Digest::MD5.hexdigest(f.read)} puts " core.android.default.melt.apk md5="+digestTmp if(digest.eql?digestTmp) puts "found in " +f+ " core.android.melt.apk md5="+digestTmp+"MATCH!" return; end end end # core.android.default.apk core.android.melt.apk core.android.v2.apk end def analyze_dex(file, dir) digest = "" digest = Digest::MD5.hexdigest(file) puts 'MD5 digest: ' + digest if !dir.nil? Dir.glob(dir+'/**/android.zip') do |f| check_md5(f, file, digest) end Dir.glob(dir+'/**/android_2*.zip') do |f| check_md5(f, file, digest) end end end ################## Main file options = {} options[:dir] = "/Volumes/SHARE/RELEASE/SVILUPPO/previous cores/" optparse = OptionParser.new do |opts| opts.banner = "extracts info from RCS zip/apk" opts.on("-p", "--pwd zip_password", "password") do |pwd| options[:pwd] = pwd end opts.on("-z", "--zip zip", "RCS zip/apk file") do |zip| options[:apkfile] = zip end opts.on("-D", "--dex dexsample", "searching only dex") do |file| options[:dex] = file end opts.on("-d", "--dir dir", "searching dir for md5 match with old core") do |file| options[:dir] = file end end optparse.parse! if options[:apkfile].nil? and options[:dex].nil? printf("usage: -z \n") printf("usage: -d \n") exit 0 elsif options[:dex].nil? and options[:dir].nil? printf("usage: -D \n") printf("usage: -d \n") exit 0 end printf("CHECKING "+ options[:apkfile] +"\n") if not options[:apkfile].nil? analyze_android(options[:apkfile].to_s, options[:dir], options[:pwd].to_s) if not options[:apkfile].nil? analyze_dex(options[:dex].to_s, options[:dir]) if not options[:dex].nil? # examples: # ../decryptRCS/extractInfo.rb -z 33ae1e1bc6596238876e167b9df67b8bd4f57bb14f08fd67048364ad3398bb17.zip -d '/Volumes/SHARE/RELEASE/SVILUPPO/previous cores/' # if the sample is a DEX # ../decryptRCS/extractInfo.rb -D 33ae1e1bc6596238876e167b9df67b8bd4f57bb14f08fd67048364ad3398bb17.zip -d '/Volumes/SHARE/RELEASE/SVILUPPO/previous cores/' .