[YU-RIS] 免封包處理
[YU-RIS] 免封包處理
0x00 背景
YURIS引擎如果大家之前有看我的文章,已經(jīng)叫大家自行去官方看看了,在官方你可以下到一個(gè)demo,名稱為yu-ris_0486_007.lzh的文件,當(dāng)然也有可能是別的版本,反正你解壓后是在一個(gè)文件夾里能看到yu-ris.exe觀察結(jié)構(gòu),發(fā)現(xiàn)這東西沒有封包也是可以運(yùn)行的,而且還能看到demo里的相關(guān)素材在游戲目錄下的文件夾里。
由此我們可以知道,這個(gè)引擎其實(shí)并不用封包就可以讀取文件,當(dāng)然其實(shí)大部分引擎都是支持的,只不過有些打包成游戲后把這種功能屏蔽了。
本篇文章的目的就是指導(dǎo)大家把yuris的免封包給搞出來(lái),以方便對(duì)里面的圖片腳本進(jìn)行替換。
0x01 版本差異
對(duì)于yuris來(lái)說(shuō),老版本的基本上都是可以直接讀取目錄下的文件的,但是得保持目錄結(jié)構(gòu)。
對(duì)于新版本的來(lái)說(shuō),會(huì)對(duì)文件讀取進(jìn)行一些限制,也就是不會(huì)直接讀取目錄下的文件
新舊版本劃分之前提過,不再贅述。
0x02 不同情況
當(dāng)然,你可以別管是新版本還是老版本,其實(shí)yuris亂改也不是一天兩天了,如果以后你看到個(gè)零幾年的游戲都不能直接讀取目錄下的文件,也沒什么驚訝的。
通常yuris能不能免封包讀取不是固定的,也就是說(shuō),它甚至可以控制到具體某一個(gè)文件是否免封包讀取,常見的情況是,你解包A封包放到目錄下可以讀取,但是B封包卻不行,這是完全正常的。
當(dāng)然要是你遇到一個(gè)情況,只有某個(gè)文件是不能免封包讀取也是完全正常的
所以我們也別管是新版本還是老版本,是能讀取還是不能讀取,先把文件放到游戲目錄下再說(shuō),如果不能讀取就說(shuō)明需要改東西了。
0x03 文件優(yōu)先級(jí)
之前我們已經(jīng)提到過yscfg.ybn這個(gè)文件,我們說(shuō)過它里面有很多有趣的東西,它位于ysbin.ypf或bn.ypf封包里。這個(gè)文件里面有個(gè)參數(shù)是控制文件讀取優(yōu)先級(jí)的,詳見這個(gè)鏈接Note.txt
yscfg.ybn (Project configuration)
=====================================
int magic = 'YSCF'
int version
int padding = 0
int compile
int screenWidth
int screenHeight
int enable
byte imageTypeSlots[8]
byte soundTypeSlots[4]
int thread
int debugMode
int sound
int windowResize
int windowFrame
int filePriorityDev
int filePriorityDebug
int filePriorityRelease
int padding = 0
short captionLength
byte caption[captionLength]
filePriorityRelease filePriorityDebug filePriorityDev這三個(gè)就是控制文件讀取優(yōu)先級(jí)的,這三個(gè)分別代表游戲在不同模式的下的文件優(yōu)先級(jí),一般大家下載的游戲都是Release的。
下面是某個(gè)游戲的yscfg.ybn文件

圖中紅色方框圈起來(lái)的就是這三個(gè)參數(shù),可以看到他們都是01開頭的,其實(shí)最后一個(gè)紅色方框的01是我改的原來(lái)是0,也就是filePriorityRelease是0,我們的目的正是在把filePriorityRelease變?yōu)?也就是和圖上一樣,這樣就可以讓游戲優(yōu)先讀取目錄下的文件了。
由于這個(gè)yscfg文件沒有像其它yst開頭的ybn文件一樣有一層xor,所以改好后直接放ysbin文件夾里就行了(通常是這樣,但肯定有不通常嘛)。
當(dāng)然這個(gè)上面還有一個(gè)叫 debugMode可以開啟游戲的debug模式,有興趣的可以去看看。
0x04 優(yōu)先級(jí)內(nèi)部原理
カサブランカの蕾 sub_463D98
v0 = !Flag1 && !FileDebugFlag;
v2 = Flag1 == 1 && !FileReleaseFlag;
v3 = (1 - v2) * (1 - v0);
if ( Flag2 != 1 && v3 )
{
v32 = 0;
v33 = 1;
v34 = 3;
v35 = 2;
}
else
{
v32 = 0;
v33 = 1;
v34 = 2;
v35 = 3;
}
for ( i = 0; i < 4; ++i )
{
v5 = *(&v32 + i);
if ( *(&v32 + i) )
{
switch ( v5 )
{
case 1:
v6 = sub_440910((int)&v28, "ysbin\\yscfg.ybn");
if ( v6 )
goto LABEL_23;
break;
case 2:
v6 = sub_440620((int)&v28, "ysbin\\yscfg.ybn"); //封包
if ( v6 )
goto LABEL_23;
break;
case 3:
v6 = sub_4405FC("ysbin\\yscfg.ybn"); //目錄
if ( (_BYTE)v6 )
{
v30 = 1;
goto LABEL_23;
}
break;
}
}
else
{
v6 = sub_440968((int)&v28, "ysbin\\yscfg.ybn");
if ( v6 )
goto LABEL_23;
}
}
隨便簡(jiǎn)略說(shuō)說(shuō),最頭上FileDebugFlag這個(gè)就是yscfg里面的filePriorityDebug release同理,這也是為什么改yscfg.ybn能夠讓游戲變成能夠直接讀取目錄下文件的原因。
v32 = 0;
v33 = 1;
v34 = 3;
v35 = 2;
其實(shí)這個(gè)就是一數(shù)組而已,你可以當(dāng)成檢索文件的順序。底下那個(gè)switch其實(shí)就是依據(jù)這個(gè)數(shù)組里的數(shù)來(lái)找到對(duì)應(yīng)的case,每個(gè)case里都有一個(gè)函數(shù),函數(shù)參數(shù)都是文件的路徑,如果某一個(gè)case里的函數(shù)執(zhí)行成功就會(huì)goto LABEL_23;如果失敗則進(jìn)入下一個(gè)循環(huán)讀取數(shù)組里的下一個(gè)元素, 這個(gè)LABEL_23;在后面,那一塊代碼是把文件讀入內(nèi)存的,太長(zhǎng)沒貼上來(lái)。
通常你不去動(dòng)的時(shí)候,是命中case 2,也就是從封包讀取,如果要走目錄下的免封包得命中case 3,如果要命中case 3最簡(jiǎn)單的方法是把 v32 = 0;改成 = 3,從這也可以知道,無(wú)論你怎么改這個(gè)數(shù)組里的四個(gè)數(shù),都要記住,其中一個(gè)必須有2,如果無(wú)法命中case 2也就是不能夠從封包里讀取,這樣你目錄下沒文件的時(shí)候游戲會(huì)讀取不到文件進(jìn)而無(wú)法啟動(dòng)或報(bào)錯(cuò)。
我是不推薦你去改這個(gè)數(shù)組里的數(shù)字的,因?yàn)檫@個(gè)地方不止一處,有非常多類似上面代碼的地方,而且都是有用的,當(dāng)然也看游戲,有些游戲沒幾處。當(dāng)然你硬要改的話,這種地方也很好定位,case 3那個(gè)走從封包讀取的函數(shù)里是這樣的
BOOL __usercall sub_4405FC@<eax>(const CHAR *a1@<eax>)
{
DWORD FileAttributesA; // eax
FileAttributesA = GetFileAttributesA(a1);
return (FileAttributesA & 0x10) == 0 && FileAttributesA != -1;
}
在IDA里可以對(duì) GetFileAttributesA()(這是一個(gè)WINAPI)這個(gè)函數(shù)按x找到使用這個(gè)函數(shù)的地方,反正很快就可以找到上面代碼差不多的地方,比如這個(gè) sub_4405FC那么對(duì)這個(gè)函數(shù)按x找到使用這個(gè)函數(shù)的地方基本上就是上面文件讀取優(yōu)先級(jí)的代碼處了。
在x64dbg里,有個(gè)搜索當(dāng)前區(qū)域內(nèi)所有調(diào)用WINAPI的call的功能,叫 Intermodular call 在搜字符串那個(gè)地方。搜一下可以找到exe里所有正常調(diào)用WINAPI的地方,然后篩選出調(diào)用GetFileAttributesA()的地方即可找到上面的位置
004405FC | 50 | push eax |
004405FD | FF15 A0705700 | call dword ptr ds:[<&GetFileAttributesA>] |
00440603 | A8 10 | test al,10 |
00440605 | 75 0B | jne casablanca.440612 |
00440607 | 83F8 FF | cmp eax,FFFFFFFF |
0044060A | 74 06 | je casablanca.440612 |
0044060C | B8 01000000 | mov eax,1 |
00440611 | C3 | ret |
對(duì)這個(gè) push eax按一下ctrl + r就能查找所有直接調(diào)用這個(gè)函數(shù)的地方了。
0x05 一些意外
上面已經(jīng)說(shuō)了,我不推薦你去改那個(gè)優(yōu)先級(jí)數(shù)組里的0 1 2 3這些東西,一是太多,二是可能你改錯(cuò)了會(huì)導(dǎo)致一些文件沒辦法讀取。
那么怎么改更好呢?剛剛我們已經(jīng)說(shuō)到了,把yscfg.ybn的filePriorityRelease改成1就可以,但是看看上面的代碼,它在yscfg.ybn還沒加載的時(shí)候就去判斷了優(yōu)先級(jí),而且是默認(rèn)為封包讀取的。當(dāng)然有一些游戲不會(huì)這樣的,是允許yscfg.ybn從文件夾讀取的,如果是這樣的話,到這里其實(shí)就完成了。
其實(shí)最初FileReleaseFlag里面是0的,也就是和我們沒改yscfg.ybn的時(shí)候是一樣,那么這時(shí)候yscfg.ybn是不會(huì)從目錄下讀取的。只有當(dāng)yscfg.ybn讀取進(jìn)來(lái)后,才會(huì)把filePriorityRelease里的數(shù)值拷貝到FileReleaseFlag里。那么這時(shí)候,我們單純的把yscfg.ybn放到游戲目錄下的ysbin文件夾內(nèi)顯然是沒有效果的。
這時(shí)候,可以搜索yscfg.ybn字符串,然后找到它的優(yōu)先級(jí)的那個(gè)數(shù)組,把第一個(gè)元素改成3即可。
00463DF3 | 75 22 | jne casablanca.463E17 |
00463DF5 | C68424 68010000 00 | mov byte ptr ss:[esp+168],0 <-改成3 |
00463DFD | C68424 69010000 01 | mov byte ptr ss:[esp+169],1 |
00463E05 | C68424 6A010000 02 | mov byte ptr ss:[esp+16A],2 |
00463E0D | C68424 6B010000 03 | mov byte ptr ss:[esp+16B],3 |
00463E15 | EB 20 | jmp casablanca.463E37 |
00463E17 | C68424 68010000 00 | mov byte ptr ss:[esp+168],0 <-改成3 |
00463E1F | C68424 69010000 01 | mov byte ptr ss:[esp+169],1 |
00463E27 | C68424 6A010000 03 | mov byte ptr ss:[esp+16A],3 |
00463E2F | C68424 6B010000 02 | mov byte ptr ss:[esp+16B],2 |
00463E37 | 33DB | xor ebx,ebx |
00463E39 | EB 01 | jmp casablanca.463E3C |
當(dāng)然我個(gè)認(rèn)為這個(gè)方法還是不夠好,還有別的方法,大家可以跟一下 filePriorityRelease的值是怎么賦給FileReleaseFlag的。

浙公網(wǎng)安備 33010602011771號(hào)