Last active
December 27, 2015 05:11
-
-
Save asm256/81d883c6b038387f7986 to your computer and use it in GitHub Desktop.
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
#unbox.rb | |
# AOIMY01形式の.box専用 | |
# .boxファイルを引数に入力すると | |
# 中身のコンパイル済み.txtと簡易デコンパイルしたdec_*.txtを出力する | |
# .boxファイルはbox.vfsやobj.vfsを展開すると手に入る | |
# 以下に256byteのメモリダンプが必要 | |
# 256 BYTE memory dump from 0x002F7640 | |
ARGSNUM = [ | |
] | |
#コンパイル済み.txtの書式 | |
#1byteのコマンド指定 | |
# コマンドによっては引数がある | |
# 引数の数はコマンドに依存する | |
#0x02(msg) : msgを表示する | |
#0x03(charname,voice=null,unk=null) : 発言者欄にcharnameを設定し、voiceを再生する | |
#0x05() : 改ページ | |
#0x07(addr,msg,unkA=null,unkB=null) : 選択肢を表示し0x05命令で止まる 選択された場合 goto addr | |
#0x0A(VAR,VAL) : 変数VARにVALをセットする | |
#0x0B(VAR,VAL,unkA=null) : 変数VARにVALを加算する | |
#0x15(addr) : goto addr | |
#0x16(addr) : call addr | |
#0x17 : return 0x16で飛んで0x17で返ってくる | |
#0x1A(cond,addr) : if(cond == false) goto addr | |
#0x2E(VAR,range_start,range_end) : VARにrange_start ~ range_end までの乱数を挿入する | |
#0x3C(msg) : システムメッセージmsgを表示する | |
#0x41(unk) : 不明 test.box(実験コーナー)みる限り画面エフェクトだと思われる unk = 2..20 | |
#0x49(moviefile) : moviefile(.dat)を再生する | |
#0x4C(imgFile,num): num番レイヤーをimgFile(.agf)で初期化する? | |
#0x4D(imgFile,num): num番レイヤーをimgFile(.agf)で上書きする? | |
# 0m0_01.txtの場合 | |
# x4c "bg001e0.agf" 10 | |
# ... | |
# x4d "bg098a0.agf" 10 | |
# x4d "bg011b0.agf" 33 | |
# ... | |
# x4d "bg098a0.agf" 10 | |
# x4d "bg008c0.agf" 33 | |
#0x52(imgFile,unkA,unkB,unkC,unkD=null,unkE=null): 立ち絵imgFileを表示する | |
#0x56(unkA,unkB,unkC=null,unkD=null): 立ち絵を消去する | |
# 0m0_01.txtの場合 | |
# x52 "ta00a00.agf" 4 4 11 null null | |
# ... | |
# x56 0xffffffff 11 null null | |
#0x6E(num,box) : boxのnum番シナリオを再生する | |
#0x76(VAR,1,0,num,box) : boxのnum番シナリオのローカル既読判定をVARに格納 | |
#0x78() : シナリオ末尾 | |
# | |
#引数指定 | |
# 引数は直前のコマンドに引数をくっつける | |
#特殊 | |
#0x00 : push NULL | |
#0x01 LL STRING[LL] : 式を計算して返り値をpush | |
#0x88 LL STRING[LL] : 文字列 | |
#一般的 | |
#0xXY | |
# X : 0 ゲーム変数 C/F/S | |
# X : 2 シナリオローカル変数CL/FL/SL | |
# X : 4 グローバル変数CG/FG/SG | |
# C/F/Sは | |
# Y=2の場合はC(数値) | |
# Y=4の場合はF(真偽値) 1でYES 0でNO | |
# Y=8の場合はS(文字列) | |
# X : 9 アドレスの指定 | |
# X : 8 数値の直接指定 | |
# | |
# Y : 1 特殊(ポインタ?) | |
# Y : 2 数値(DWORD) | |
# Y : 4 数値(BYTE) | |
# Y : 8 文字列 | |
#作ってみたがほとんど使わなかった | |
def zread_ucs2(buf) | |
dst = "" | |
pos = 0 | |
len = buf.length | |
pos += 2 until buf[pos,2] == "\0\0" || len <= pos | |
return buf[0,pos] , buf[pos+2..len] | |
end | |
def box_calc(num , pos , esi, val) | |
val2 = ((pos >> val) & 15) | |
left = num >> (val2 + 1) & 0x7fffffff | |
right= num << (31 - val2) & 0xffffffff | |
(left + right + esi) & 0xffffffff | |
end | |
def decrypt_box(buf,pos,size) | |
b = buf.unpack("C*") | |
size.times{|i| | |
esi = (pos - 0x5CC8E9D7) & 0xffffffff | |
num1 = (0xA3371629 >> ((pos & 15) + 1)) - ((0x5CC8E9D7 << (31 - (pos & 15))) & 0xffffffff) + esi | |
num1 = num1 & 0xffffffff | |
num2 = box_calc(num1 , pos , esi , 4) | |
num3 = box_calc(num2 , pos , esi , 8) | |
num4 = box_calc(num3 , pos , esi , 12) | |
num5 = box_calc(num4 , pos , esi , 16) | |
num6 = box_calc(num5 , pos , esi , 20) | |
num7 = box_calc(num6 , pos , esi , 24) | |
num8 = box_calc(num7 , pos , esi , 28) | |
key = num8 >> (pos & 15) | |
# puts <<EOS | |
#num1 = #{num1.to_s 16} | |
#num2 = #{num2.to_s 16} | |
#num3 = #{num3.to_s 16} | |
#num4 = #{num4.to_s 16} | |
#num5 = #{num5.to_s 16} | |
#num6 = #{num6.to_s 16} | |
#num7 = #{num7.to_s 16} | |
#num8 = #{num8.to_s 16} | |
#key = #{(key & 0xff).to_s 16} | |
#EOS | |
b[i] ^= key & 0xFF | |
pos += 1 | |
} | |
b.pack "C*" | |
end | |
def print_number_type t | |
case t | |
when 9 | |
"&" | |
when 8 | |
"" | |
when 4 | |
"CG" | |
when 2 | |
"CL" | |
when 1 | |
"CP" | |
when 0 | |
"C" | |
end | |
end | |
def print_number type , number | |
t = type >> 4 | |
tt = (type & 4 == 4 ? "F" : | |
type & 2 == 2 ? "C" : | |
type & 8 == 8 ? "S" : "@") | |
case t | |
when 9 | |
return "ERROR(F&#{number.to_s 16})" if type & 4 != 0 | |
"&" + "000000#{number.to_s 16}"[-6,6] + "h" | |
when 8 | |
number | |
when 4 | |
"#{tt}G" + "000#{number}"[-3,3] | |
when 2 | |
"#{tt}L" + "000#{number}"[-3,3] | |
when 1 | |
"#{tt}P" + "000#{number}"[-3,3] | |
when 0 | |
"#{tt}" + "000#{number}"[-3,3] | |
else | |
puts "[unknown_type: #{type},number:#{number}]" | |
return "[unknown_type: #{type},number:#{number}]" | |
end | |
end | |
def decompile_arg txtbuf , i , argLen | |
arg = [] | |
argLen.times{ | |
type = txtbuf[i] | |
#puts "#{i.to_s 16} : #{type.to_s 16}" | |
if type & 2 != 0 then | |
if type & 0x80 != 0 then | |
buf = txtbuf[i+1,4].pack "C*" | |
tmp = buf.unpack("L>").first | |
i += 5 | |
if type & 0x01 != 0 then | |
puts "[unknown 3 @pos = 0x#{i.to_s 16} , @type = 0x#{type.to_s 16}]" | |
else | |
tmp = print_number type , tmp | |
end | |
else | |
# 2byte 読み込み? | |
buf = txtbuf[i+1,2].pack "C*" | |
i += 3 | |
tmp = buf.unpack("S>").first | |
if type & 0x01 != 0 then | |
#0x23を確認 | |
#puts "unknown 2 @pos = 0x#{i.to_s 16} , @type = 0x#{type.to_s 16}" | |
#CG(CL(005) + 03) + 100 | |
vtype = type | |
begin | |
tmp2 = txtbuf[i+1,2].pack("C*").unpack("s>").first | |
tmp = "#{print_number_type(type >> 4)}(#{tmp})+#{tmp2}" | |
vtype = txtbuf[i] | |
i += 3 | |
end while vtype & 1 != 0 | |
#vtype & 1 != 0 の時再帰的に変数 | |
else | |
tmp = print_number type , tmp | |
end | |
end | |
arg.push tmp | |
elsif type & 4 != 0 | |
if type & 0x80 != 0 | |
tmp = txtbuf[i+1] | |
i += 2 | |
else | |
#2byte読み込み | |
tmp = txtbuf[i+1,2].pack("C*").unpack("s>").first | |
i += 3 | |
end | |
tmp = print_number type , tmp | |
arg.push tmp | |
elsif type & 8 != 0 | |
if type & 0x80 != 0 | |
len = txtbuf[i+1] | |
tmp = '"' + txtbuf[i+2,len*2].pack("C*").unpack("v*").pack("U*") + '"' | |
i += 2 + len * 2 | |
else | |
tmp = txtbuf[i+1,2].pack("C*").unpack("s>").first | |
i += 3 | |
tmp = "#{print_number(type , tmp)}" | |
#puts "unknown 8 @pos = 0x#{i.to_s 16} , @type = 0x#{type.to_s 16}" if tmp != 0 | |
#p txtbuf[i,16] | |
end | |
arg.push tmp | |
elsif type & 1 != 0 | |
# 実際には計算して結果を引数に格納してる | |
len = txtbuf[i+1] | |
arg.push 'eval(`' + txtbuf[i+2,len*2].pack("C*").unpack("v*").pack("U*").strip + '`)' | |
i += 2 + len * 2 | |
else | |
i += 1 | |
arg.push nil | |
puts "unknown @pos = 0x#{i.to_s 16} , @type = 0x#{type.to_s 16}" if type != 0 | |
end | |
} | |
return i , arg | |
end | |
def to_my_s obj | |
r = "" | |
if obj.nil? then | |
r += "null" | |
elsif obj.kind_of? String | |
r += obj | |
elsif obj.kind_of? Array | |
r += "[" | |
array_sep = false | |
obj.each{|x| | |
r += " , " if array_sep | |
r += to_my_s x | |
} | |
r += "]" | |
elsif obj.kind_of? Integer | |
if obj > 256 | |
r += "0x#{obj.to_s 16}" | |
else | |
r += obj.to_s | |
end | |
else | |
r += obj.to_s | |
end | |
r | |
end | |
def decompile_txt txt | |
len = txt.size | |
txtbuf = txt.unpack("C*") | |
buffer = "" | |
i = 0 | |
begin | |
buffer += "00000000#{i.to_s 16}"[-6,6] + ":" | |
cmd = txtbuf[i] | |
i+=1 | |
arg = [] | |
argLen = ARGSNUM[cmd] | |
i,arg = decompile_arg txtbuf,i,argLen | |
if cmd == 0 then | |
p "cmd(0) have arg" unless arg.empty? | |
end | |
buffer += "x#{cmd.to_s 16}" | |
arg.each{|a| | |
buffer += " #{to_my_s a}" | |
} | |
buffer += "\n" | |
end while len > i | |
buffer | |
end | |
def unbox target | |
org_buf = File.binread target | |
header,buf = zread_ucs2(org_buf) | |
return unless header.unpack("v*").pack( "U*") == "AOIMY01" | |
file_num , unk_header, buf = buf.unpack("NNa*") | |
#puts "file_num = #{file_num.to_s 16}\n" | |
file_num.times{ | |
#struct{ | |
# UCHAR name[16]; | |
# DWORD offset; | |
# DWORD size; | |
#} | |
vname = buf.unpack("v16") | |
pos,size,buf = buf.unpack("@32NNa*") | |
name_len = vname.find_index 0 || 16 | |
name = vname[0,name_len].pack("U*") | |
puts "\t#{name}" | |
File.binwrite(name , decrypt_box(org_buf[pos,size] , pos,size)) | |
File.binwrite("dec_#{name}" , decompile_txt(decrypt_box(org_buf[pos,size] , pos,size))) | |
} | |
end | |
ARGV.each{|t| | |
puts "input: #{t}" | |
unbox t | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment