Profil de lovefun童话PhotosBlogListes Outils Aide

Blog


25 octobre

恶魔城的一些破解问题

1) 有关编码
; 取高字节
0209385C E200CCFF and     r12,r0,0FF00h                           ;1  70
02093860 E1A0C42C mov     r12,r12,lsr 8h                          ;1  71
;减掉0x81
02093864 E24CC081 sub     r12,r12,81h                             ;1  72
;乘以0x1318,加到字库首地址
02093868 E021139C mla     r1,r12,r3,r1                            ;4  76
;取低字节
0209386C E20000FF and     r0,r0,0FFh                              ;1  77
;如果比0x7E大,就减掉1
02093870 E350007E cmp     r0,7Eh                                  ;1  78
02093874 82400001 subhi   r0,r0,1h                                ;1  79
;再减0x40
02093878 E2403040 sub     r3,r0,40h                               ;1  80
;乘以0x1A
0209387C E0201293 mla     r0,r3,r2,r1                             ;3  83
02093880 E12FFF1E bx      r14                                     ;3  86
所以,游戏从rom中解密编码的过程可以写为(Python语言):
def L2S(l):
    sdata = l % 256
    hdata = l / 256
    if sdata > 0x7e:
        sdata -= 1
    return sdata + (hdata-0x81)*0xbc - 0x40
另外编写一个逆运算,也就是加密过程(这里有不少细节疑问,我认为只要解密的结果一样,加密就是对的):
def S2L(s):
    s = s + 0x40
    low_number = s % 0xbc
    hi_number  = s / 0xbc
    if low_number > 0x7e:
        low_number += 1
    if low_number < 0x40:
        low_number += 0xbd
        hi_number -= 1
    return low_number + (hi_number + 0x81) * 256
2)关于字库的缩容
碰到字库大就会引起烧录卡死机的情形。为了尽量减小字库容量,要拼命缩容。本来一个字模26个字节,其中最初的两个字节是无用编码,有人(flyeyes?)提议去掉这两个字节,于是,首先参见游戏显示部分的代码,有一句很重要:
 
02095180 E59F31D8 ldr     r3,=1318h                               ;注意0x1318=0x1A*0xBC
 
另外还有一句ldr r4,=1Ah之类的,一时找不到。将这两个分别改成0x18*0xBC和0x18即可。另外注意整个字库最前面还是需要有2字节的无用编码。
 
3)关于汉化编程
在快速处理方面,得益于Python的快速开发特性。强烈建议有VB等经验的破解员学习Python。附上文本解密导出的程序
 
# coding:utf8
import os,sys
def Output(f, now_index, now_loc):
#    f.write ("========================\n")
    f.write ("index: " + str(now_index) + '\n')
    f.write ("loc:   " + hex(now_loc) + '\n')
    f.write ("--------------------\n")
def S2L(s):
    s = s + 0x40
    low_number = s % 0xbc
    hi_number  = s / 0xbc
    if low_number > 0x7e:
        low_number += 1
    if low_number < 0x40:
        low_number += 0xbd
        hi_number -= 1
    return low_number + (hi_number + 0x81) * 256
def L2S(l):
    sdata = l % 256
    hdata = l / 256
    if sdata > 0x7e:
        sdata -= 1
    return sdata + (hdata-0x81)*0xbc - 0x40
# 换行
ChLine = int("F006",16)
# 结束
ChEnd  = int("F00A",16)
# S-JIS码表
table = {}
f = file("SJIS.txt",)
for data in f:
#    data = f.readline()
    # find the "=" place
    for i in range(len(data)):
        if data[i] == "=":
            break
#    print data, i
    address = int(data[:i],16)
    value = data[i+1:-1]
    table[address] = value
f.close()
# 相对码表
xtable = {}
f = file("ld937714.dat","rb")
fo = file("newtable.txt","w")
data = " "
number = 0
while True:
    data = f.read(2)
    if len(data)<2:
        break
    address = ord(data[1]) + ord(data[0])*256
    if address == 0:
        break
    value = table[address]
    xtable[number] = value
    s_number = number + 0x40
    low_number = s_number % 0xbc
    hi_number  = s_number / 0xbc
    if low_number > 0x7e:
        low_number += 1
    if low_number < 0x40:
        low_number += 0xbd
        hi_number -= 1
    s_number = low_number + (hi_number + 0x81) * 256
#    fo.write(hex(number)+"="+hex(s_number)+"="+value+"\n")
    fo.write(hex(s_number)[2:]+"="+value+"\n")
    number += 1
    data = f.read(24)
fo.close()
f.close()
# 文本
f = file("overlay9_0000.bin","rb")
fo = file("textout.txt","w")
ft = file("old_index.txt","w")
now_index = 0
now_loc = 0
pointer = 0
data = " "
Output(fo, now_index, now_loc)
sig = True
while True:
    data = f.read(2)
    if len(data) < 2:
        break
    sdata = ord(data[0])
    if sdata > 0x7e:
        sdata -= 1
    address = ord(data[0]) + ord(data[1])*256
    s_address = sdata + (ord(data[1])-0x81)*0xbc - 0x40
    if address == ChLine:
        fo.write('\n')
    elif address == ChEnd:
        fo.write('\n')
#        fo.write ("--------------------\n\n")
        fo.write ("====================\n\n")
        now_index += 1
        now_loc = pointer + 2
        Output(fo, now_index, now_loc)
        ft.write (str(now_index) + " " + hex(now_loc)[2:] + "\n")
    elif address == 0:
        if sig == False:
            fo.write('{0}')
    elif xtable.has_key(s_address):
        fo.write(xtable[s_address])
#        if xtable[s_address] == "遥":
#            print hex(address), hex(s_address), ord(data[0]), ord(data[1])
    else:
        fo.write('{' + hex(address)[2:] + '}')
#    else:
#        print "Error\n"
#        print now_index, now_loc, data, hex(address)
    if address == ChEnd or address == 0:
        sig = True
    else:
        sig = False
    pointer += 2
ft.close()
fo.close()
f.close()
14 octobre

今天画的asymptote图

还在用metapost的linuxer们……该改用asympote了。
import solids;
import math;

size(0,200);
real r=1;
real h=1;

real s1 = 0.8, s2 = 0.6;
real s21, s22;

s21 = s2 * sin(0.76);
s22 = s2 * cos(0.76);

revolution R=sphere(r);
R.filldraw(white,3,0.3black);
pen edge=blue+0.25mm;
draw((0,r,0)--(0,0,0),W,edge);
draw("$x_1$",(0,r,0),S,edge);
draw((r,0,0)--(0,0,0),W,edge);
draw("$x_2$",(r,0,0),SW,edge);
draw((0,0,r)--(0,0,0),W,edge);
draw("$x_3$",(0,0,r),SW,edge);

pen rd=red+0.25mm;
draw((s2,s1,0) .. (0,s1,s2) .. (-s2,s1,0) .. (0,s1,-s2) ..cycle, rd);
draw((s21,s1,s22) .. (0,0,0), rd+dashed);
draw("$\theta$",0.45(s21,s1,s22), S);
draw((s21,s1,s22) .. (0,s1,0), rd+dashed);
draw((s2,s1,0) .. (0,s1,0), rd+dashed);
draw("$\varphi$",0.3(s21,s1,s22)+0.7(0,s1,0), S);
dot((s21,s1,s22));


13 octobre

NDS OAM相关的内存解释

OAM是精灵(sprite)映射表的储存位置。某些游戏中文本可能会以精灵的形式存在,所以也许需要跟踪精灵的内存变化。根据相关资料和我的分析,叙述如下:

OAM分两块区域:下屏(main screen)从0x07000000起。上屏(sub screen)从0x07000400起。每个屏最多有128个精灵,每个精灵的映射表8个字节,其中前6个字节意义比较重要,举例说明:

0C 40 10 00 A8 04

(1)精灵在屏幕上的位置:
X_Loc:0x0C (第一个字节)
Y_Loc:0x10 (第三个字节)

(2)精灵的大小:
精灵的大小由第二字节的最高两个Bit(Shape位)和第四字节的最高两个Bit(Size位)共同决定。可能还和其他的scale位有关,没有具体研究。最终对应的大小可能有12种(最后三种应该是一种放大):
8*8, 8*16, 8*32, 16*8, 16*16, 16*32, 32*8, 32*16, 32*32, 32*64, 64*32, 64*64

(3)精灵Tile在内存中的位置(这个对汉化比较重要):
Tile_Index:A8 (第五个字节)
如为下屏,对应0x06400000+0x20*Tile_Index
如为上屏,对应0x06600000+0x20*Tile_Index

另外有个疑问:GBA的ROM在内存中整体有个映射区域,NDS的ROM则是怎么放入内存的,或者是游戏过程中动态读入,有没有人研究过这个问题?我没有找到相关资料。
1 octobre

python中的部分专用类方法

一部分在dive into python这本书里面已经有介绍了,更多的部分在Python Reference Manual中

__new__( cls[, ...])
 
__init__( self[, ...])

这两个构造函数还是有所不同的,一般都用后者吧……

__del__( self)

析构函数。好在python的内存管理很优秀,一般不用析构函数来释放内存,因而用的也少。注意del x这样的语句并不直接调用析构函数。


__repr__( self)

__str__( self)
这两个函数都是为了实现print之类的语句而准备的。

__cmp__( self, other)
所有比较操作的重载。在早期版本中也可以用__lt__, __ge__之类的6个运算符分别重载

__hash__( self)
应该是用在hash表的时候,实现自定义hash算法


__nonzero__( self)
应该是用于 if x之类的语句中,返回True或False。如果这个函数没有定义,那么根据__len__的结果处理(如果定义了的话)

__getattr__( self, name)
__setattr__( self, name, value)
__delattr__( self, name)
用于a = x.attr,x.attr = a 和 del x.attr 的操作

__getitem__( self, key)
__setitem__( self, key, value)
__delitem__( self, key)
类似dictionary的操作: a = x[item], x[item] = a, del x[item]

__len__( self)
被len(x)调用

__add__( self, other)

__sub__( self, other)

__mul__( self, other)

__floordiv__( self, other)

__mod__( self, other)

__divmod__( self, other)

__pow__( self, other[, modulo])

__lshift__( self, other)

__rshift__( self, other)

__and__( self, other)

__xor__( self, other)

__or__( self, other)
运算符重载……重要。这些符号是用于 x + y 这样的语句中的 x 方

__div__( self, other)
除法重载

__radd__( self, other)

__rsub__( self, other)

__rmul__( self, other)

__rdiv__( self, other)

__rtruediv__( self, other)

__rfloordiv__( self, other)

__rmod__( self, other)

__rdivmod__( self, other)

__rpow__( self, other)

__rlshift__( self, other)

__rrshift__( self, other)

__rand__( self, other)

__rxor__( self, other)

__ror__( self, other)
和上面不同的是,这些运算符被重载到 x + y 这样的语句的 y 方,且只有 x 的运算符未被定义时才调用

__iadd__( self, other)

__isub__( self, other)

__imul__( self, other)

__idiv__( self, other)

__itruediv__( self, other)

__ifloordiv__( self, other)

__imod__( self, other)

__ipow__( self, other[, modulo])

__ilshift__( self, other)

__irshift__( self, other)

__iand__( self, other)

__ixor__( self, other)

__ior__( self, other)
自加,自乘等运算

__neg__( self)

__pos__( self)

__abs__( self)

__invert__( self)
一元操作符重载: -x, +x, abs(x), ~x

__complex__( self)

__int__( self)

__long__( self)

__float__( self)
函数complex(x), int(x), long(x), float(x)重载

__oct__( self)

__hex__( self)
函数oct(x), hex(self)重载