Gecko格式
Wii有不同的内存區域,不過衹有2個被遊戲使用(也被金手指使用):
MEM1: 從0x80000000到0x81800000
MEM2: 從0x90000000到0x94000000
然而,MEM2的頂部是無法訪問的(嘗試從那兒讀寫會使Wii死機)。那得取決於遊戲,但似乎你可以自由訪問從0x90000000到0x93400000的區域。
ba:基地址。每次代碼處理器執行後設置在0x80000000。每次基地址會加上一個代碼地址,代碼處理器執行:地址=地址+(基地址&0xFE000000)。你可以更改它,但如果你這麼幹了,別忘了事後還原成它本來的値。
po:指針。每次代碼處理器執行後設置在0x80000000。每次指針會加上一個代碼地址,代碼處理器執行:地址=地址+指針。你可以隨意更改它。
grN:“Gecko寄存器N”。它不是一個眞正的寄存器類似r0或r1。它是個32bits的値,因爲Gecko在内存中保留了一片區域存放N。N可以是0x0到0xF的値。你可以在裡面存儲/載入任意値,但要注意其它的代碼可能會覆蓋你的値。別指望代碼處理器每次也會執行它。如果你希望存儲一個不能被改變的値,嘗試用代碼處理器以外的眞正的地址,或用46/4E結合goto代碼類型。注意grN比gecko/代碼處理器優先被存儲。那意味著它們總是在一個靜態地址上被訪問:0x80001804,[0x80001804]=gr0,[0x80001808]=gr1,……,[0x80001840]=grF。你可以直接訪問它們,例如在插入一個彙編指令時。
bN:“區塊N”。一個區塊由2個32bits的値組成。它們用來存儲重復/返回/轉到/轉到下一子程序代碼的信息。比如b0的數據存儲在0x80001844,b1的在0x8000184C……
CT:代碼類型。範圍從0到7。它是一個代碼的第一個數字的開頭3個bit(譯者按:從最低位數起)。因爲這個你會注意到代碼的所有代碼類型事實上被乘以2:CT 1:2……,CT 2:4……,CT 3:6……,CT 7:E。第4個bit用來告訴代碼處理器使用指針還是基地址。那意味著你可以通過觀察代碼的第一個數字知道基地址是否被使用。如果是偶數就是基地址,如果是奇數就是指針。
CST:代碼子類型。它是一個代碼的第二個數字的開頭3個bit(譯者按:從最低位數起)。因爲這個你會注意到代碼的所有代碼子類型事實上被乘以2:CST1:2……,CST2:4……,CST3:6……,CST7:E。第4個bit事實上是地址 (____)的一部分。
____:它是一些將被使用的代碼的地址部分。它的範圍從0x00000000到0x01FFFFFF。事實上“____”被稱作地址是不完整的,圍繞在“____”周圍的一些數字也是地址的一部分。比如0x00FFFFFF以上的部分,地址會變更代碼子類型中的“look”部分,把它標記成一個奇數。
[]:比如[XXXXXXXX]。括弧把XXXXXXXX定義爲内存區域,不是一個値。所以[XXXXXXXX]表示“存儲在XXXXXXXX上的數據”。無論如何括弧内的値必須是個有效地址,否則Wii會死機。
+=:比如pa+=XXXXXXXX表示pa=pa+XXXXXXXX。
對條件代碼(If……)來說所有的比較都是無符號的,這表示數字範圍是從0x00000000到0xFFFFFFFF,然而遊戲有時會用有符號的數字。比如你在遊戲中的X坐標會從1到0再到-1,在16進制中表示從0x00000001到0x00000000再到0xFFFFFFFF。所以由於代碼處理器使用無符號的數字,在這種情況下你必須先尋找一個“小於”値(從0x00000001到0x00000000),然後才是“大於”値。
你會找到代碼類型盡可能詳細的完整列表。爲了幫助新來的理解代碼類型,有需要時我把類型分成了使用基地址和使用指針的。
做代碼前的一點建議,特別是使用指針時:在寫入你從内存中載入的値到一個地址時確保地址是有效的。代碼處理器不檢查地址範圍的,如果地址是錯的仍會盲目地寫入(接著Wii死機)。 看來Wii的内存是重度的被使用/被塡充,一個用來存儲地址的地方也會稍後被用來存儲數據。那表示檢查地址是否是00000000的機制並不是一直有效的。
所以在你寫入從内存載入的値到一個地址前你必須確保地址是有效的。可以用CE/DE If……代碼類型來判斷。
舉例:
對MEM1:
CE000000 80008180:檢查基地址是否在[80000000,81800000]範圍内。
DE000000 80008180 :檢查指針是否在[80000000,81800000]範圍内。
對MEM2:
CE000000 90009340:檢查基地址是否在[90000000,93400000]範圍内。
DE000000 90009340:檢查指針是否在[90000000,93400000]範圍内。
如果你想檢查基地址/指針是在MEM1還是MEM2内:
CE000000 80008180:檢查基地址是否在[80000000,81800000]範圍内。
66000001 00000000:如果代碼執行後的狀態是true則跳過下一行。
CE000001 90009340:結束上一個判斷,然後檢查基地址是否在[90000000,93400000]。
DE000000 80008180:檢查指針是否在[80000000,81800000]。
66000001 00000000:如果代碼執行後的狀態是true則跳過下一行。
DE000001 90009340 :結束上一個判斷,然後檢查指針是否在[90000000,93400000]。
那表示你先載入你要的數據,然後用一個(或多個)CE/DE代碼是否是一個有效地址。
同樣的卽使指針有時被某些遊戲重度地使用,有時不可能找到一個穩定的指針。比如《超級馬里奧銀河》,每個角色有他們自己的數據,所有的數據是動態的,不可能找到靜態的地址,在這些特殊的情況下你除了用彙編指令修改外別無選擇。還是在《超級馬銀》中,每個角色有他們自己的AI程序。通過找到你要的角色的程序並hook它,你會得到訪問它的指針(通常存儲在Wii的寄存器中)。你也可以把指針寫入一個已知的、修正的位置,然後用它和別的代碼一起去修改角色的數據,或寫一個起同樣的修改效果的彙編程序。
所以緊記指針是很危險的,人們總是認爲他們找到了衹對自己起效的眞指針但往往是假指針。
確保多測試幾次依賴指針的代碼,必須改變等級、角色的代碼,甚至新建一個存檔來測試。如果效果停止了(卽使沒發生可見的副作用)或在某個點引起死機了,別再使用它了(嘗試去找個新的指針或用彙編修改遊戲)。別發表還沒被重度確認/測試的代碼。
CT0:直接寫入/塡充到内存
CST0:8bits寫入&塡充
00______ YYYY00XX:8bits内存寫入&塡充到(基地址)
把連續的YYYY+1個XX寫入到基地址+地址
10______ YYYY00XX:8bits内存寫入&塡充到(指針)
把連續的YYYY+1個XX寫入到指針+地址
CST1:16bits寫入&塡充
02______ YYYYXXXX:16bits内存寫入&塡充到(基地址)
把連續的YYYY+1個XXXX寫入到基地址+地址
12______ YYYYXXXX:16bits内存寫入&塡充到(指針)
把連續的YYYY+1個XXXX寫入到指針+地址
CST2:32bits寫入
04______ XXXXXXXX:32bits内存寫入到(基地址)
把XXXXXXXX寫入到基地址+地址
14______ XXXXXXXX:32bits内存寫入到(指針)
把XXXXXXXX寫入到指針+地址
CST3:字符串代碼
06______ YYYYYYYY:把代碼d1d2d3d4 d5d6d7d8……補丁到(基地址)
把d1d2d3d4 d5d6d7d8……寫入到基地址+地址。YYYYYYYY是寫入的字節數。
16______ XXXXXXXX:把代碼d1d2d3d4 d5d6d7d8……補丁到(指針)
把d1d2d3d4 d5d6d7d8……寫入到指針+地址。YYYYYYYY是寫入的字節數。
CST4:壓縮碼
08______ 000000XX:8bits壓縮碼(基地址)
0NNNZZZZ VVVVVVVV
把NNN+1個字節的XX寫入基地址+地址,然後XX+=VVVVVVVV(XX=XX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
18______ 000000XX:8bits壓縮碼(指針)
0NNNZZZZ VVVVVVVV
把NNN+1個字節的XX寫入指針+地址,然後XX+=VVVVVVVV(XX=XX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
08______ 0000XXXX:16bits壓縮碼(基地址)
1NNNZZZZ VVVVVVVV
把NNN+1個雙字節的XXXX寫入基地址+地址,然後XXXX+=VVVVVVVV(XXXX=XXXX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
18______ 0000XXXX:16bits壓縮碼(指針)
1NNNZZZZ VVVVVVVV
把NNN+1個雙字節的XXXX寫入指針+地址,然後XXXX+=VVVVVVVV(XXXX=XXXX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
08______ XXXXXXXX:32bits壓縮碼(基地址)
2NNNZZZZ VVVVVVVV
把NNN+1個四字節的XXXXXXXX寫入基地址+地址,然後XXXXXXXX+=VVVVVVVV(XXXXXXXX=XXXXXXXX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
18______ XXXXXXXX:32bits壓縮碼(指針)
2NNNZZZZ VVVVVVVV
把NNN+1個四字節的XXXXXXXX寫入指針+地址,然後XXXXXXXX+=VVVVVVVV(XXXXXXXX=XXXXXXXX+VVVVVVVV),地址+=ZZZZ(地址=地址+ZZZZ)
CT1 常規條件代碼 (16/32 bits)
CST0:32bits如果等於
20______ YYYYYYYY:32bits如果等於(基地址)
比較[基地址+地址]上的32bits値是否等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
30______ YYYYYYYY:32bits如果等於(指針)
比較[指針+地址] 上的32bits値是否等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
20_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果等於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的32bits値是否等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
30_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果等於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的32bits値是否等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST1:32bits如果不等於
22______ YYYYYYYY:32bits如果不等於(基地址)
比較[基地址+地址]上的32bits値是否不等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
32______ YYYYYYYY:32bits如果不等於(指針)
比較[指針+地址]上的32bits値是否不等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
22_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果不等於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的32bits値是否不等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
32_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果不等於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的32bits値是否不等於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST2:32bits如果大於
24______ YYYYYYYY:32bits如果大於(基地址)(有符號)
比較[基地址+地址]上的32bits値是否大於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
34______ YYYYYYYY:32bits如果大於(指針)(有符號)
比較[指針+地址]上的32bits値是否大於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
24_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果大於(基地址)(有符號)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的32bits値是否大於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
34_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果大於(指針)(有符號)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的32bits値是否大於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST3:32bits如果小於
26______ YYYYYYYY:32bits如果小於(基地址)(有符號)
比較[基地址+地址]上的32bits値是否小於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
36______ YYYYYYYY:32bits如果小於(指針)(有符號)
比較[指針+地址]上的32bits値是否小於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
26_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果小於(基地址)(有符號)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的32bits値是否小於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
36_____1 YYYYYYYY:上一個條件碼的結束行,然後32bits如果小於(指針)(有符號)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的32bits値是否小於YYYYYYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST4:16bits如果等於
28______ ZZZZYYYY:16bits如果等於(基地址)
比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
(譯者按:ZZZZ充當了掩碼,如果用來判斷Joker Adress的話可以用ZZZZ忽略掉不想判斷的Joker Digits。下同。)
38______ ZZZZYYYY:16bits如果等於(指針)
比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
28_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果等於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
38_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果等於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST5:16bits如果不等於
2A______ ZZZZYYYY:16bits如果不等於(基地址)
比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否不等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3A______ ZZZZYYYY:16bits如果不等於(指針)
比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否不等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
2A_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果不等於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否不等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3A_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果不等於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否不等於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST6:16bits如果大於
2C______ ZZZZYYYY:16bits如果大於(基地址)
比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否大於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3C______ ZZZZYYYY:16bits如果大於(指針)
比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否大於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
2C_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果大於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否大於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3C_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果大於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否大於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
CST7:16bits如果小於
2E______ ZZZZYYYY:16bits如果小於(基地址)
比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否小於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3E______ ZZZZYYYY:16bits如果小於(指針)
比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否小於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
2E_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果小於(基地址)
作爲上一個條件碼的結束行,然後比較[基地址+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否小於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。
3E_____1 ZZZZYYYY:上一個條件碼的結束行,然後16bits如果小於(指針)
作爲上一個條件碼的結束行,然後比較[指針+地址] 上的値同ZZZZ(ZZZZ要先作邏輯非運算)邏輯與運算的結果是否小於YYYY。如果是,下面的代碼將被執行(否則下面的代碼不執行)。