让天之痕窗口化运行!
生活随笔
收集整理的這篇文章主要介紹了
让天之痕窗口化运行!
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
說明:游戲版本是簡體中文2.02版,其它版本估計部分地址不完全一樣,僅作參考。
??
??這個游戲比較古老了,用的DirectDraw來繪制2D圖像,在創建DirectDraw對象之后,調用SetCooperativeLevel函數來確定是否全屏顯示。但是SetCooperativeLevel這個函數沒有在DDRAW.DLL的輸出表里面,直接下斷點找不到,只能對DirectDrawCreate下斷點了。下斷之后運行,一開始的對話框中選擇繼續游戲,程序中斷在DDRAW.DLL里面,回到程序,來到:
??0043C0E0????????????51??????????????PUSH????ECX
??0043C0E1????????????56??????????????PUSH????ESI
??0043C0E2????????????8D4424?04???????LEA?????EAX,DWORD?PTR?SS:[ESP+4]
??0043C0E6????????????6A?00???????????PUSH????0
??0043C0E8????????????50??????????????PUSH????EAX
??0043C0E9????????????8BF1????????????MOV?????ESI,ECX
??0043C0EB????????????6A?00???????????PUSH????0
??0043C0ED????????????C74424?10?00000>MOV?????DWORD?PTR?SS:[ESP+10],0
??0043C0F5????????????E8?16400600?????CALL????<JMP.&DDRAW.DirectDrawCreate>
??0043C0FA????????????85C0????????????TEST????EAX,EAX
??0043C0FC????????????74?1A???????????JE??????SHORT?swd3_ar.0043C118
??
??0043C118????????????8B4424?04???????MOV?????EAX,DWORD?PTR?SS:[ESP+4]
??0043C11C????????????56??????????????PUSH????ESI????????????????????????????;?lpDD,保存在4C5B28
??0043C11D????????????68?A0B24A00?????PUSH????swd3_Ful.004AB2A0
??0043C122????????????50??????????????PUSH????EAX????????????????????????????;?剛創建的DirectDraw對象
??0043C123????????????8B10????????????MOV?????EDX,DWORD?PTR?DS:[EAX]
??0043C125????????????FF12????????????CALL????DWORD?PTR?DS:[EDX]?????????????;?<DDRAW.DD_QueryInterface(x,x,x)>
??0043C127????????????85C0????????????TEST????EAX,EAX
??
??往下走,返回之后來到:
??
??0043C05E????????????E8?7D000000?????CALL????<swd3_win.CreateDDraw>
??0043C063????????????83F8?01?????????CMP?????EAX,1??????????????????????????????;?在這里返回
??0043C066????????????75?24???????????JNZ?????SHORT?swd3_win.0043C08C
??0043C068????????????817C24?18?214E0>CMP?????DWORD?PTR?SS:[ESP+18],4E21?????????;?比較
??0043C070????????????75?05???????????JNZ?????SHORT?swd3_win.0043C077????????????;?把這個跳轉NOP掉
??0043C072????????????6A?08???????????PUSH????8??????????????????????????????????;?窗口模式應該從這里走
??0043C074????????????57??????????????PUSH????EDI
??0043C075????????????EB?09???????????JMP?????SHORT?swd3_win.0043C080
??0043C077????????????8B86?84000000???MOV?????EAX,DWORD?PTR?DS:[ESI+84]
??0043C07D????????????6A?13???????????PUSH????13?????????????????????????????????;?全屏模式從這里走
??0043C07F????????????50??????????????PUSH????EAX
??0043C080????????????8BCE????????????MOV?????ECX,ESI
??0043C082????????????E8?C9000000?????CALL????swd3_win.0043C150??????????????????;?里面會調用SetCooperativeLevel
??0043C087????????????83F8?01?????????CMP?????EAX,1
??0043C08A????????????74?09???????????JE??????SHORT?swd3e.0043C095???????????????;?下面是全屏運行時的設置顯示分辨率了,要跳走,改為43C0B8
??0043C08C????????????5F??????????????POP?????EDI
??
??
??
??在43C068這里比較,如果是窗口模式就PUSH?8,全屏就PUSH?13,因此把這個跳轉NOP掉。執行完SetCooperativeLevel之后,是按全屏顯示來處理,要設置顯示分辨率。窗口模式就不需要了,但是需要調用設置窗口裁減器等函數,還好本來就有這么一段程序,在43C0B8處開始,因此43C095改為43C0B8。
??運行看一下效果吧:
??
??
??確實是窗口運行了,但是成這個鬼樣子了。想一下,原來游戲內部圖像都是16位處理的,直接改成窗口之后,內部的Surface都已經是32位了,但是數據還是16位的,所以顯示完全不對了。所以在顯示之前要把16位的Buffer改成32位的。這個轉換過程要在所有繪圖已經完成往主表面上貼的時候進行,這樣才不會漏掉任何東西。所以要首先找到主表面的地址。從上面設置顯示模式的地方繼續往下走,來到:
??
??0043C0B8?????????????????????8BCE????????????MOV?????ECX,ESI???????????????????????????????;?<swd3_Ful.lpDD>
??0043C0BA?????????????????????E8?E1010000?????CALL????<swd3_Ful.CreateMainSurf>?????????????;?這個里面創建主表面,F7跟進
??0043C0BF?????????????????????83F8?01?????????CMP?????EAX,1
??0043C0C2?????????????????????74?09???????????JE??????SHORT?swd3_Ful.0043C0CD
??
??43C0BA處F7跟進,來到
??
??0043C3DE?????????????????????8B06????????????MOV?????EAX,DWORD?PTR?DS:[ESI]
??0043C3E0?????????????????????BD?7C000000?????MOV?????EBP,7C
??0043C3E5?????????????????????52??????????????PUSH????EDX????????????????????????????;?lpDDSurface
??0043C3E6?????????????????????8D5424?1C???????LEA?????EDX,DWORD?PTR?SS:[ESP+1C]
??0043C3EA?????????????????????896C24?1C???????MOV?????DWORD?PTR?SS:[ESP+1C],EBP
??0043C3EE?????????????????????C74424?20?01000>MOV?????DWORD?PTR?SS:[ESP+20],1????????;?DDSD_CAPS
??0043C3F6?????????????????????C78424?84000000>MOV?????DWORD?PTR?SS:[ESP+84],2200?????;?DDSCAPS_PRIMARYSURFACE?|?DDSCAPS_3DDEVICE
??0043C401?????????????????????8B08????????????MOV?????ECX,DWORD?PTR?DS:[EAX]
??0043C403?????????????????????52??????????????PUSH????EDX????????????????????????????;?lpDDrawSurfaceDesc
??0043C404?????????????????????50??????????????PUSH????EAX????????????????????????????;?lpDD
??0043C405?????????????????????FF51?18?????????CALL????DWORD?PTR?DS:[ECX+18]??????????;?<DDRAW.DD_CreateSurface4(x,x,x,x)>
??0043C408?????????????????????85C0????????????TEST????EAX,EAX????????????????????????;?創建主表面完成,保存在4C5B2C
??0043C40A?????????????????????74?15???????????JE??????SHORT?swd3_Ful.0043C421
??
??繼續往下走,來到:
??
??0043C496?????????????50??????????????PUSH????EAX
??0043C497?????????????6A?00???????????PUSH????0
??0043C499?????????????FFD7????????????CALL????EDI
??0043C49B?????????????50??????????????PUSH????EAX
??0043C49C?????????????8BCE????????????MOV?????ECX,ESI
??0043C49E?????????????E8?8D010000?????CALL????<swd3_Ful.CreatOffScreenSurfac>???????;創建和主頁面一樣大小的離屏表面,保存在4C5B30,這個函數是后面創建離屏表面時多次調用的函數,加上標簽方便后面識別。
??0043C4A3?????????????8946?08?????????MOV?????DWORD?PTR?DS:[ESI+8],EAX
??
??先F9運行游戲,再對4C5B2C下硬件訪問斷點,中斷在0043C8E5:
??
??0043C8C0?<swd3_ar>??8B4424?04???????MOV?????EAX,DWORD?PTR?SS:[ESP+4]????;這段程序從這里開始,獲取一個表面的指針,作上記號GetSurfacePtr
??0043C8C4????????????2D?11270000?????SUB?????EAX,2711
??...
??0043C8DF????????????C2?0400?????????RETN????4
??0043C8E2????????????8B41?04?????????MOV?????EAX,DWORD?PTR?DS:[ECX+4]
??0043C8E5????????????C2?0400?????????RETN????4???????????????????????????;從這里返回,返回的指針就是主表面的指針
??
??取消硬件斷點,查找所有調用GetSurfacePtr的地方,在所有參考下斷點,運行幾次后來到:
??
??00408B94????????????E8?273D0300?????CALL????<swd3_ar.GetSurfacePtr>
??00408B99????????????8B0D?646E4C00???MOV?????ECX,DWORD?PTR?DS:[4C6E64]
??00408B9F????????????8B10????????????MOV?????EDX,DWORD?PTR?DS:[EAX]
??00408BA1????????????6A?00???????????PUSH????0?????????????????????????????;?在這里開始打補丁,5DE000
??00408BA3????????????68?00000001?????PUSH????1000000???????????????????????;?DDBLT_WAIT
??00408BA8????????????6A?00???????????PUSH????0?????????????????????????????;?SrcRect
??00408BAA????????????51??????????????PUSH????ECX???????????????????????????;?lpSrcSurface
??00408BAB????????????6A?00???????????PUSH????0?????????????????????????????;?DestRect
??00408BAD????????????50??????????????PUSH????EAX???????????????????????????;?lpDestSurface
??00408BAE????????????FF52?14?????????CALL????DWORD?PTR?DS:[EDX+14]?????????;?<DDRAW.DD_Surface_Blt(x,x,x,x,x,x)>
??00408BB1????????????C3??????????????RETN
??
??這里就是向主表面繪圖的代碼了,要在調用Blt函數之前把SrcSurface轉換成32位的Surface。
??首先要寫一個轉換的函數,并導入到主程序的輸入表,方便后面調用。
??
??005DE000????????????60??????????????PUSHAD
??005DE001????????????51??????????????PUSH????ECX
??005DE002????????????FF15?98D15D00???CALL????DWORD?PTR?DS:[<ConvertSurface>;?Swd3e.ConvertSurface
??005DE008????????????61??????????????POPAD
??005DE009????????????6A?00???????????PUSH????0
??005DE00B????????????68?00000001?????PUSH????1000000
??005DE010????????????6A?00???????????PUSH????0
??005DE012??????????-?E9?93ABE2FF?????JMP?????swd3_ar.00408BAA??????????????;?跳回去
??
??運行看一下:
??
??主要的顏色對了,但是圖像大小還不正確,原因是Blt函數的第二個參數DestRect是0,所以顯示到整個屏幕上去了,應該把這個參數設成窗口大小。需要在程序一開始時先保存一下窗口大小,在游戲一開始選擇對話框返回之后保存。查找DialogBoxParamA,下斷點:
??
??0040A66C????????????50??????????????PUSH????EAX
??0040A66D????????????FF15?9CA14A00???CALL????DWORD?PTR?DS:[<&USER32.Dialog>;?游戲一開始的對話框,在這里下斷點
??0040A673????????????48??????????????DEC?????EAX???????????????????????????;?返回之后馬上設置窗口位置并保存,5DE080
??0040A674????????????74?2E???????????JE??????SHORT?swd3_ar.0040A6A4
??0040A676????????????48??????????????DEC?????EAX
??0040A677????????????74?21???????????JE??????SHORT?swd3_ar.0040A69A
??0040A679????????????83E8?04?????????SUB?????EAX,4
??
??005DE080????????????60??????????????PUSHAD
??005DE081????????????A1?44634E00?????MOV?????EAX,DWORD?PTR?DS:[4E6344]????????????;?4E6344保存著窗口的名柄
??005DE086????????????50??????????????PUSH????EAX
??005DE087????????????FF15?4CD15D00???CALL????DWORD?PTR?DS:[<CenterWindow>]????????;?使窗口位置居中,內含保存窗口位置
??005DE08D????????????61??????????????POPAD
??005DE08E????????????48??????????????DEC?????EAX
??005DE08F??????????-?0F84?0FC6E2FF???JE??????swd3_ar.0040A6A4
??005DE095????????????48??????????????DEC?????EAX
??005DE096??????????-?0F84?FEC5E2FF???JE??????swd3_ar.0040A69A
??005DE09C????????????83E8?04?????????SUB?????EAX,4
??005DE09F??????????-?0F85?ABC3E2FF???JNZ?????swd3_ar.0040A450
??005DE0A5??????????-?E9?D8C5E2FF?????JMP?????swd3_ar.0040A682
??
??把上面5DE000作一下修改:
??
??005DE000????????????60??????????????PUSHAD
??005DE001????????????51??????????????PUSH????ECX
??005DE002????????????FF15?58D15D00???CALL????DWORD?PTR?DS:[<ConvertSurface>]??????;?Swd3e.ConvertSurface
??005DE008????????????61??????????????POPAD
??005DE009????????????6A?00???????????PUSH????0
??005DE00B????????????68?00000001?????PUSH????1000000
??005DE010????????????6A?00???????????PUSH????0
??005DE012????????????51??????????????PUSH????ECX
??005DE013????????????891D?D0DF5F00???MOV?????DWORD?PTR?DS:[<varSurfConv>],EBX
??005DE019????????????8B1D?4CD15D00???MOV?????EBX,DWORD?PTR?DS:[<rcWindow>]????????;?Swd3e.rcWindow
??005DE01F????????????53??????????????PUSH????EBX
??005DE020????????????8B1D?D0DF5F00???MOV?????EBX,DWORD?PTR?DS:[<varSurfConv>]
??005DE026????????????50??????????????PUSH????EAX
??005DE027????????????FF52?14?????????CALL????DWORD?PTR?DS:[EDX+14]
??005DE02A??????????-?E9?82ABE2FF?????JMP?????swd3_win.00408BB1
??
??一不小心點到窗口外面了,再恢復時怎么窗口位置又回去了?這個就比較簡單了,查找SetWindowPos函數,改成我們自己寫的CenterWindow函數就可以了,這個函數在40AF6A處,這里不再詳述。
??再運行一下:
??
??差不多快好了,但是中間怎么是花的呢?原來這些地方都是半透明的,程序中Alpha處理函數是按16位處理的,現在變成32位的,沒有進行修改。Alpha處理要針對每一個點的RGB進行處理,一般會調用GetPixelFormat函數,在這個地方:
??
??00427253????????????C74424?1C?20000>MOV?????DWORD?PTR?SS:[ESP+1C],20
??0042725B????????????C74424?20?40000>MOV?????DWORD?PTR?SS:[ESP+20],40
??00427263????????????FF51?54?????????CALL????DWORD?PTR?DS:[ECX+54]????????????????;?GetPixelFormat
??00427266????????????8B6C24?2C???????MOV?????EBP,DWORD?PTR?SS:[ESP+2C]????????????;?藍色掩碼
??0042726A????????????8B5C24?28???????MOV?????EBX,DWORD?PTR?SS:[ESP+28]????????????;?綠色掩碼
??0042726E????????????8B7424?24???????MOV?????ESI,DWORD?PTR?SS:[ESP+24]????????????;?紅色掩碼
??00427272????????????EB?1B???????????JMP?????SHORT?swd3_ar.0042728F???????????????;?這里NOP掉
??00427274????????????BE?007C0000?????MOV?????ESI,7C00
??00427279????????????BB?E0030000?????MOV?????EBX,3E0
??0042727E????????????BD?1F000000?????MOV?????EBP,1F
??
??上面取得RGB的掩碼之后判斷16位色下RGB各自的位數并作處理,16位色分555,565,556等多種模式,都統一成555來處理,由于改成32位色了,所以RGB的掩碼都不對了。把427272處NOP掉,默認為555色進行處理。
??再看一下:
??
??終于顏色都正常了。隨便讀一個檔開始游戲吧,結果一讀進去怎么又花了?原來大地圖和相聚檔時的轉換色深不在一個地方啊!按上面同樣方面修改,一共要修改大地圖,系統設置界面,物品買賣,戰斗等幾處。
??修改完成之后重新進行吧,發現所有字符都變成只有一半了:
??
??字符顯示一般會用到TextOut函數,在這個函數處下斷點,被斷下之后,發現是從439DB0處開始的,這個函數的作用是在一個離屏表面上繪制一個字符。這個表面是在439D2E處創建的,大小是64X64像素:
??
??00439D2C??????????8B0E????????????MOV?????ECX,DWORD?PTR?DS:[ESI]
??00439D2E??????????E8?FD280000?????CALL????<swd3_Ful.CreatOffScreenSurface(w>;?顯示一個字符用的臨時Surface
??00439D33??????????8B0E????????????MOV?????ECX,DWORD?PTR?DS:[ESI]
??
??往下走,來到:
??
??00439D68????????????FF52?58?????????CALL????DWORD?PTR?DS:[EDX+58]????????????????;?<DDRAW.DD_Surface_GetSurfaceDesc4(x,x)>
??00439D6B????????????8B4424?18???????MOV?????EAX,DWORD?PTR?SS:[ESP+18]????????????;?一行的字節數
??00439D6F????????????8B5424?10???????MOV?????EDX,DWORD?PTR?SS:[ESP+10]
??00439D73????????????D1F8????????????SAR?????EAX,1????????????????????????????????;?16位頁面右移一位變成一行的點數,32位要右移兩位
??00439D75????????????8996?DC0F0000???MOV?????DWORD?PTR?DS:[ESI+FDC],EDX
??
??從TextOutA函數往下找,來到:
??
??0043B3B9????????????8BCE????????????MOV?????ECX,ESI
??0043B3BB????????????E8?F0E9FFFF?????CALL????<swd3_ar.PrintChar>
??0043B3C0????????????8BCE????????????MOV?????ECX,ESI
??0043B3C2????????????E8?49FFFFFF?????CALL????swd3_ar.0043B310?????????????????????;?F7跟進
??
??...
??0043B31C????????????896C24?08???????MOV?????DWORD?PTR?SS:[ESP+8],EBP
??0043B320????????????50??????????????PUSH????EAX
??0043B321????????????E8?0AC4FDFF?????CALL????swd3_ar.00417730?????????????????????;?F7跟進后發現此函數是取得一個表面的數據指針
??0043B326????????????894424?10???????MOV?????DWORD?PTR?SS:[ESP+10],EAX
??0043B32A????????????8B83?D40F0000???MOV?????EAX,DWORD?PTR?DS:[EBX+FD4]
??
??在43B321處取得TextOutA寫入的字符表面的數據地址,下面就要對字符的數據進行處理了。在頁面創建和顯示字符時都是32位的,下面處理是16位的,要先把這個字符的表面改成16位的,補丁打在5DE380處:
??
??005DE380????????????E8?AB93E3FF?????CALL????<swd3_ar.GetSurfaceBuffer>
??005DE385????????????60??????????????PUSHAD
??005DE386????????????6A?40???????????PUSH????40
??005DE388????????????6A?40???????????PUSH????40
??005DE38A????????????50??????????????PUSH????EAX
??005DE38B????????????FF15?60D15D00???CALL????DWORD?PTR?DS:[<ButterTo16>]??????????;?Swd3e.BufferTo16,把32位的Surface數據轉換成16位的
??005DE391????????????61??????????????POPAD
??005DE392??????????-?E9?8FCFE5FF?????JMP?????swd3_ar.0043B326
??005DE397????????????90??????????????NOP
??
??這下字符顯示正常了。玩了一段時間之后,發現進系統界面的物品欄時,成了這個鬼樣子:
??
??
??字符的樣子正常,高度和Y坐標都變成了原來的一半,應該是向主背景頁面寫的時候出了問題。
??上面一開始創建主頁完成之后,馬上就會創建一個640X480大小的離屏背景頁面,很容易找到它的數據指針保存在4EE564處(作個記號為BackBuffer)。先在TextOutA處下斷點,斷下之后往下走,注意觀察信息窗口有沒有顯示BackBuffer的地址,一直來到這里:
??
??0043B899????????????8B4C24?28???????MOV?????ECX,DWORD?PTR?SS:[ESP+28]
??0043B89D????????????52??????????????PUSH????EDX??????????????????????????????????;?Y坐標
??0043B89E????????????8D042F??????????LEA?????EAX,DWORD?PTR?DS:[EDI+EBP]
??0043B8A1????????????53??????????????PUSH????EBX??????????????????????????????????;?X坐標
??0043B8A2????????????50??????????????PUSH????EAX
??0043B8A3????????????51??????????????PUSH????ECX??????????????????????????????????;?離屏頁面數據地址,4EE564處的值
??0043B8A4????????????8BCE????????????MOV?????ECX,ESI
??0043B8A6????????????E8?A5EFFFFF?????CALL????swd3_ar.0043A850?????????????????????;?F7跟進,往下走,注意信息窗口
??
??F7跟進之后往下走,注意信息窗口出現離屏頁面的數據地址,來到:
??
??0043A931????????????8B56?14?????????MOV?????EDX,DWORD?PTR?DS:[ESI+14]
??0043A934????????????8B4424?20???????MOV?????EAX,DWORD?PTR?SS:[ESP+20]
??0043A938????????????33DB????????????XOR?????EBX,EBX
??0043A93A????????????8B1402??????????MOV?????EDX,DWORD?PTR?DS:[EDX+EAX]
??0043A93D????????????8B4424?30???????MOV?????EAX,DWORD?PTR?SS:[ESP+30]????????????;?取到離屏頁面的起始地址
??0043A941????????????03D1????????????ADD?????EDX,ECX??????????????????????????????;?加上X坐標
??0043A943????????????8D3450??????????LEA?????ESI,DWORD?PTR?DS:[EAX+EDX*2]?????????;?目標點位置
??0043A946????????????8B4424?40???????MOV?????EAX,DWORD?PTR?SS:[ESP+40]
??
??在43A943處取得地址,是要往頁面上寫字符的點了。但是由于每個字符都要跑過這里一遍,不方便下斷點,所以想了一個笨辦法,打個補丁寫到一個文件里面。最終發現位置出錯時,在43A943處的EDX值不對,進一步跟蹤發現正常時43A931處取得的EDX指向的值都是500,出錯時變成了280,在這里打一個補丁,修正一下這個值,這里就不貼出代碼了。
??顯示正常字符時也會調用這里,所以還要設一個標志,從這個函數返回幾次之后可以來到:
??
??0044FEEA????????????B9?50634E00?????MOV?????ECX,swd3_ar.004E6350
??0044FEEF????????????E8?ACB6FEFF?????CALL????<swd3_ar.ShowString_Buf>?????????????;?在指定位置顯示一個字符串
??0044FEF4????????????46??????????????INC?????ESI
??
??在44FEEF處調用前設置一個標志,調用完之后改回來,可以解決字符位置不對的問題。物品,裝備,奇術,符鬼等界面在大地圖上對話之后字符位置不對的地方都用此方法修改。涉及到的顯示字符的函數除了上面43A850處外,還有43AB00和43AEE0兩處,也用同樣方法修改。
??上面修改完之后,基本不影響正常游戲了,但是顯示ANI動畫時還是會花屏,這同樣是由于頁面沒有轉換的原因,如下圖:
??
??
??先運行游戲,在顯示ANI動畫前對CreateFileA下斷點,直到堆棧中顯示ANI文件名,取消斷點。對BackBuffer的第一個字下硬件寫入斷點,運行后來到:
??
??00415DFA????????????8B15?702A4D00???MOV?????EDX,DWORD?PTR?DS:[4D2A70]
??00415E00????????????33C9????????????XOR?????ECX,ECX
??00415E02????????????8A0E????????????MOV?????CL,BYTE?PTR?DS:[ESI]?????????????????;?每次取一個字節
??00415E04????????????83C0?02?????????ADD?????EAX,2????????????????????????????????;?要寫入的目標地址
??00415E07????????????46??????????????INC?????ESI??????????????????????????????????;?源加1
??00415E08????????????4F??????????????DEC?????EDI??????????????????????????????????;?所有的數據數
??00415E09????????????66:8B0C4A???????MOV?????CX,WORD?PTR?DS:[EDX+ECX*2]
??00415E0D????????????66:8948?FE??????MOV?????WORD?PTR?DS:[EAX-2],CX???????????????;?寫到目標地址里面
??00415E11??????????^?75?E7???????????JNZ?????SHORT?swd3_ar.00415DFA
??
??從上面看到,這里寫到BackBuffer里面是連續的,而顯示到屏幕上的頁面應該是一行一行的,所以要進行相應的轉換,在函數返回前415E23處進行轉換,具體代碼就不貼了。
??更改之后發現畫面成了這個樣子:
??
??
??圖像大小對了,但是好像背景不正確,這是由于ANI動畫的每一幀不是完全重畫,只是重畫有圖像變化的部分,所以要在上面那個函數的一開始時先恢復前一幀的圖像。上面那一個函數從415D40處開始,在這里打補丁:
??
??005DE240????????????60??????????????PUSHAD
??005DE241????????????B9?00B00400?????MOV?????ECX,4B000????????????????????????????;?頁面大小
??005DE246????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[4EE564]????????????;?BackBuffer
??005DE24C????????????A1?88D15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpTemp>]??????????;?在ConvertANISurface里面保存的每一幀圖像
??005DE251????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE253????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>;?前一幀圖像恢復到BackBuffer里面
??005DE255????????????61??????????????POPAD
??005DE256????????????51??????????????PUSH????ECX
??005DE257????????????8B0D?941E4B00???MOV?????ECX,DWORD?PTR?DS:[4B1E94]
??005DE25D????????????53??????????????PUSH????EBX
??005DE25E????????????55??????????????PUSH????EBP
??005DE25F????????????56??????????????PUSH????ESI
??005DE260????????????57??????????????PUSH????EDI
??005DE261??????????-?E9?E57AE3FF?????JMP?????swd3_ar.00415D4B
??
??這下ANI顯示正常了,但是ANI里面有對話時又成了這樣:
??
??
??從上面的函數返回兩次之后,發現是從413137處調用的,ANI中出現對話之后在這里下斷,中斷后F7跟進,來到:
??
??00415A2E????????????57??????????????PUSH????EDI
??00415A2F????????????0F84?FF020000???JE??????swd3_ar.00415D34?????????????????????;?直接返回
??00415A35????????????392D?18724C00???CMP?????DWORD?PTR?DS:[4C7218],EBP
??00415A3B????????????0F85?B7020000???JNZ?????swd3_ar.00415CF8?????????????????????;?對話時從這里跳走
??
??00415CF8????????????A1?20294D00?????MOV?????EAX,DWORD?PTR?DS:[<Ani_Talk_Flag>]???;?是否已經保存過對話時的背景,第一次對話時要保存
??00415CFD????????????B9?00580200?????MOV?????ECX,25800????????????????????????????;?大小
??00415D02????????????3BC5????????????CMP?????EAX,EBP
??00415D04????????????75?20???????????JNZ?????SHORT?swd3_ar.00415D26???????????????;?第一次進入對話時不跳
??00415D06????????????8B35?64E54E00???MOV?????ESI,DWORD?PTR?DS:[<BackBuffer>]??????;?第一次對話時保存背景頁面
??00415D0C????????????8B3D?AC1D4D00???MOV?????EDI,DWORD?PTR?DS:[<Ani_Temp_Mem>]
??00415D12????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>
??....
??00415D26????????????8B35?AC1D4D00???MOV?????ESI,DWORD?PTR?DS:[<Ani_Temp_Mem>]????;?不是第一次進入對話就恢復
??00415D2C????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[<BackBuffer>]
??00415D32????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>
??
??上面保存應該是轉換ANI背景之后的頁面,所以保存的地方需要修改:
??
??005DE200????????????60??????????????PUSHAD
??005DE201????????????A1?8CD15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpSurf_Temp32>]
??005DE206????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE208????????????8B3D?AC1D4D00???MOV?????EDI,DWORD?PTR?DS:[<ANI_Mem>]
??005DE20E????????????B9?00B00400?????MOV?????ECX,4B000?????????????????????????????????????;32位的頁面,要增大一倍
??005DE213????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS:[ESI]
??005DE215????????????A1?8CD15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpSurf_Temp32>]
??005DE21A????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE21C????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[<BackBuffer>]
??005DE222????????????B9?00B00400?????MOV?????ECX,4B000
??005DE227????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS:[ESI]????;也要同時傳到BackBuffer里面
??005DE229????????????61??????????????POPAD
??005DE22A??????????-?E9?E57AE3FF?????JMP?????swd3_win.00415D14
??
??注意由于頁面變成32位的,大小增加了一倍,所以把25800改成了4B000,前面415CFD處的25800也要改成4B000。這時要注意分配的內存也要增加一倍才行,往上面找到分配內存的地方直接修改即可(42EEC6和42EED5)。
??快完成了!這時全屏Alpha的地方只有一半了,如下圖:
??
??
??這個直接搜索push?4B000,改為96000即可。改了之后發現455124,455134,4527AB這幾處不能改,會跳出,再改回來即可。
??同樣戰斗時上半部分淡入淡出,搜索push?3C000,改為push?78000。
??其它幾個小修改:
??買賣東西時下半部分是花屏的:
??No.1
??4550E7,4550F1處96000改為12C000,分配內存
??No.2
??45510C,45514B,456287處25800改為4B000,拷貝內存
??No.3
??455124,455134處4B000改為96000,Alpha混合
??
??存檔時的縮略圖:
??0040E41F??????????^\75?F1???????????JNZ?????SHORT?swd3_win.0040E412
??0040E421????????????05?000F0000?????ADD?????EAX,0F00????????;改為2300
??0040E426????????????4E??????????????DEC?????ESI
??
??按P鍵時保存圖片,不影響游戲正常進行,我用了一個笨辦法,自己重新寫了一個保護圖片的函數,后來想可以直接修改程序里面原來的函數的,不想再弄了。
??
??到此基本結束收工,順便把免CD做了吧。一共要修改下面幾處:
??檢查光盤卷標,412023處:
??JNZ?????SHORT?swd3_win.00412038?????;改為JMP
??地圖數據從硬盤讀:
??0042A877???????????|68?60234D00?????PUSH????swd3_win.004D2360
??0042A87C???????????|68?A8214B00?????PUSH????swd3_win.004B21A8???????????;?ASCII?"%sswd3e\%s"
??改為:
??0042A877????????????68?B4364C00?????PUSH????swd3_win.004C36B4???????????;EXE根目錄
??0042A87C????????????68?98114B00?????PUSH????swd3_win.004B1198???????????;?ASCII?"%s%s"
??
??ANI動畫從硬盤讀:
??ANI動畫從硬盤讀:
??No.1
??0042ED8C???????????|68?60234D00?????PUSH????swd3_win.004D2360
??改為:
??0042ED8C????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??No.2
??0042ED98????????????68?00284B00?????PUSH????swd3_win.004B2800???????????;?ASCII?"swd3e\Video\"
??改為:
??0042ED98????????????68?06284B00?????PUSH????swd3_win.004B2806???????????;?ASCII?"Video\"
??No.3:
??0042EDA8????????????8803????????????MOV?????BYTE?PTR?DS:[EBX],AL????????;把盤符換成光驅的盤符,直接NOP掉
??
??開始游戲時從硬盤讀地圖:
??004336D7????????????68?60234D00?????PUSH????swd3_win.004D2360
??004336DC????????????68?A8214B00?????PUSH????swd3_win.004B21A8?????????????????????????;?ASCII?"%sswd3e\%s"
??改為:
??004336D7????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??004336DC????????????68?98114B00?????PUSH????swd3_win.004B1198?????????????????????????;?ASCII?"%s%s"
??
??BIK文件從硬盤讀取:
??No.1
??0049C789????????????68?60234D00?????PUSH????swd3_win.004D2360
??改為:
??0049C789????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??No.2
??0049C795????????????68?00284B00?????PUSH????swd3_win.004B2800???????????????????????;?ASCII?"swd3e\Video\"
??改為:
??0049C795????????????68?06284B00?????PUSH????swd3_win.004B2806???????????????????????;?ASCII?"Video\"
??No.3直接NOP掉,替換盤符
??0049C7A5????????????884D?00?????????MOV?????BYTE?PTR?SS:[EBP],CL
??
??
??最后,附上SWD3E.DLL中幾個用到的函數說明:
??1.SaveBitmap32,把一個32位的頁面保存成位圖
??2.CenterWindow,主窗口居中顯示,同時把窗口位置保存在rcWindow中,并且會限制鼠標只能在游戲窗口中移動
??3.rcWindow,保存窗口位置,方便向窗口傳送圖像時使用
??4.ConvertSurface,把一個16位的頁面轉換成32位,要求原來的16位頁面是按行顯示的
??5.ConvertANIBuf,把ANI動畫的頁面轉換成按行顯示的頁面,供ConvertSurface使用
??6.BufferTo16,把一個32位的頁面轉換成16位的頁面,主要在顯示字符時使用
??7.PrintText,在一個頁面指定位置處顯示字符串,調試時使用
??8.DebugMsg,向Debug.txt文件中輸出調試信息
??9.lpTemp,ANI動畫時保存每幀原始數據,供下一幀恢復數據時使用
??10.lpTemp32,ANI動畫時保存轉換完成的數據,供ANI中的對話時恢復背景使用
??
??附上修改后的EXE文件和SWD3E.DLL文件。
??附件的EXE還有一個BUG,戰斗時敵人死亡時有時會跳出,三個以上敵人,最下面一個死去之后四面散開時(不是向左散開),會出現內存寫入錯誤。還沒有搞明白怎么回事,所以還沒有改。
2009-10-08解決此BUG,四面散開時散點的Y坐標會大于窗口高度,由于原來是全屏,所以窗口高度就是屏幕高度,現在改成窗口了,這里的最大值只能到窗口高度.
解決辦法:搜索常量0B54,把所有涉及到比較的地方都改成與1E0相比較,共有439103,4393C6,4394B1,439622,4396BF,439746,4397A7共七處.
同時把原來比較難看的宋體字改成比較好看的字體了.
??免CD之后的Huge.lmf文件要放在游戲根目錄下,BIK和ANI動畫要放在Video文件夾下!
??另外,還放了一個小小的彩蛋啦,不影響游戲畫面,這里就賣個關子啰!
??
--------------------------------------------------------------------------------
【經驗總結】
??由于DDRAW.DLL的導出函數很少,一開始不知道從何下手。某年月日突然用IDA把DDRAW.DLL打開了,一打開就提示我是否到
??MS$的網站上去下載符號表,這一下就發現快了很多。看來MS$有時還是很對得起勞苦大眾啊!
??幾個難點:
??1.字符顯示,找了好久才搞明白
??2.Alpha混色,一開始是想找到對應的函數進行修改,搞了好久發現太慢,突然來了靈感,改成用現在方法,果然有效
??3.字符位置不對,想了N種辦法也沒找到是從哪里出的錯,只好用現在這樣打補丁了
??4.現在還有一個問題,播放BIK動畫時會出錯。無奈水平不夠,還一點頭緒也沒有,反正BIK動畫也不影響游戲體驗,就懶得
??管了,等以后水平提高了有精力再去搞吧。
??
??終于寫完了,太累了,收工!
??
??這個游戲比較古老了,用的DirectDraw來繪制2D圖像,在創建DirectDraw對象之后,調用SetCooperativeLevel函數來確定是否全屏顯示。但是SetCooperativeLevel這個函數沒有在DDRAW.DLL的輸出表里面,直接下斷點找不到,只能對DirectDrawCreate下斷點了。下斷之后運行,一開始的對話框中選擇繼續游戲,程序中斷在DDRAW.DLL里面,回到程序,來到:
??0043C0E0????????????51??????????????PUSH????ECX
??0043C0E1????????????56??????????????PUSH????ESI
??0043C0E2????????????8D4424?04???????LEA?????EAX,DWORD?PTR?SS:[ESP+4]
??0043C0E6????????????6A?00???????????PUSH????0
??0043C0E8????????????50??????????????PUSH????EAX
??0043C0E9????????????8BF1????????????MOV?????ESI,ECX
??0043C0EB????????????6A?00???????????PUSH????0
??0043C0ED????????????C74424?10?00000>MOV?????DWORD?PTR?SS:[ESP+10],0
??0043C0F5????????????E8?16400600?????CALL????<JMP.&DDRAW.DirectDrawCreate>
??0043C0FA????????????85C0????????????TEST????EAX,EAX
??0043C0FC????????????74?1A???????????JE??????SHORT?swd3_ar.0043C118
??
??0043C118????????????8B4424?04???????MOV?????EAX,DWORD?PTR?SS:[ESP+4]
??0043C11C????????????56??????????????PUSH????ESI????????????????????????????;?lpDD,保存在4C5B28
??0043C11D????????????68?A0B24A00?????PUSH????swd3_Ful.004AB2A0
??0043C122????????????50??????????????PUSH????EAX????????????????????????????;?剛創建的DirectDraw對象
??0043C123????????????8B10????????????MOV?????EDX,DWORD?PTR?DS:[EAX]
??0043C125????????????FF12????????????CALL????DWORD?PTR?DS:[EDX]?????????????;?<DDRAW.DD_QueryInterface(x,x,x)>
??0043C127????????????85C0????????????TEST????EAX,EAX
??
??往下走,返回之后來到:
??
??0043C05E????????????E8?7D000000?????CALL????<swd3_win.CreateDDraw>
??0043C063????????????83F8?01?????????CMP?????EAX,1??????????????????????????????;?在這里返回
??0043C066????????????75?24???????????JNZ?????SHORT?swd3_win.0043C08C
??0043C068????????????817C24?18?214E0>CMP?????DWORD?PTR?SS:[ESP+18],4E21?????????;?比較
??0043C070????????????75?05???????????JNZ?????SHORT?swd3_win.0043C077????????????;?把這個跳轉NOP掉
??0043C072????????????6A?08???????????PUSH????8??????????????????????????????????;?窗口模式應該從這里走
??0043C074????????????57??????????????PUSH????EDI
??0043C075????????????EB?09???????????JMP?????SHORT?swd3_win.0043C080
??0043C077????????????8B86?84000000???MOV?????EAX,DWORD?PTR?DS:[ESI+84]
??0043C07D????????????6A?13???????????PUSH????13?????????????????????????????????;?全屏模式從這里走
??0043C07F????????????50??????????????PUSH????EAX
??0043C080????????????8BCE????????????MOV?????ECX,ESI
??0043C082????????????E8?C9000000?????CALL????swd3_win.0043C150??????????????????;?里面會調用SetCooperativeLevel
??0043C087????????????83F8?01?????????CMP?????EAX,1
??0043C08A????????????74?09???????????JE??????SHORT?swd3e.0043C095???????????????;?下面是全屏運行時的設置顯示分辨率了,要跳走,改為43C0B8
??0043C08C????????????5F??????????????POP?????EDI
??
??
??
??在43C068這里比較,如果是窗口模式就PUSH?8,全屏就PUSH?13,因此把這個跳轉NOP掉。執行完SetCooperativeLevel之后,是按全屏顯示來處理,要設置顯示分辨率。窗口模式就不需要了,但是需要調用設置窗口裁減器等函數,還好本來就有這么一段程序,在43C0B8處開始,因此43C095改為43C0B8。
??運行看一下效果吧:
??
??
??確實是窗口運行了,但是成這個鬼樣子了。想一下,原來游戲內部圖像都是16位處理的,直接改成窗口之后,內部的Surface都已經是32位了,但是數據還是16位的,所以顯示完全不對了。所以在顯示之前要把16位的Buffer改成32位的。這個轉換過程要在所有繪圖已經完成往主表面上貼的時候進行,這樣才不會漏掉任何東西。所以要首先找到主表面的地址。從上面設置顯示模式的地方繼續往下走,來到:
??
??0043C0B8?????????????????????8BCE????????????MOV?????ECX,ESI???????????????????????????????;?<swd3_Ful.lpDD>
??0043C0BA?????????????????????E8?E1010000?????CALL????<swd3_Ful.CreateMainSurf>?????????????;?這個里面創建主表面,F7跟進
??0043C0BF?????????????????????83F8?01?????????CMP?????EAX,1
??0043C0C2?????????????????????74?09???????????JE??????SHORT?swd3_Ful.0043C0CD
??
??43C0BA處F7跟進,來到
??
??0043C3DE?????????????????????8B06????????????MOV?????EAX,DWORD?PTR?DS:[ESI]
??0043C3E0?????????????????????BD?7C000000?????MOV?????EBP,7C
??0043C3E5?????????????????????52??????????????PUSH????EDX????????????????????????????;?lpDDSurface
??0043C3E6?????????????????????8D5424?1C???????LEA?????EDX,DWORD?PTR?SS:[ESP+1C]
??0043C3EA?????????????????????896C24?1C???????MOV?????DWORD?PTR?SS:[ESP+1C],EBP
??0043C3EE?????????????????????C74424?20?01000>MOV?????DWORD?PTR?SS:[ESP+20],1????????;?DDSD_CAPS
??0043C3F6?????????????????????C78424?84000000>MOV?????DWORD?PTR?SS:[ESP+84],2200?????;?DDSCAPS_PRIMARYSURFACE?|?DDSCAPS_3DDEVICE
??0043C401?????????????????????8B08????????????MOV?????ECX,DWORD?PTR?DS:[EAX]
??0043C403?????????????????????52??????????????PUSH????EDX????????????????????????????;?lpDDrawSurfaceDesc
??0043C404?????????????????????50??????????????PUSH????EAX????????????????????????????;?lpDD
??0043C405?????????????????????FF51?18?????????CALL????DWORD?PTR?DS:[ECX+18]??????????;?<DDRAW.DD_CreateSurface4(x,x,x,x)>
??0043C408?????????????????????85C0????????????TEST????EAX,EAX????????????????????????;?創建主表面完成,保存在4C5B2C
??0043C40A?????????????????????74?15???????????JE??????SHORT?swd3_Ful.0043C421
??
??繼續往下走,來到:
??
??0043C496?????????????50??????????????PUSH????EAX
??0043C497?????????????6A?00???????????PUSH????0
??0043C499?????????????FFD7????????????CALL????EDI
??0043C49B?????????????50??????????????PUSH????EAX
??0043C49C?????????????8BCE????????????MOV?????ECX,ESI
??0043C49E?????????????E8?8D010000?????CALL????<swd3_Ful.CreatOffScreenSurfac>???????;創建和主頁面一樣大小的離屏表面,保存在4C5B30,這個函數是后面創建離屏表面時多次調用的函數,加上標簽方便后面識別。
??0043C4A3?????????????8946?08?????????MOV?????DWORD?PTR?DS:[ESI+8],EAX
??
??先F9運行游戲,再對4C5B2C下硬件訪問斷點,中斷在0043C8E5:
??
??0043C8C0?<swd3_ar>??8B4424?04???????MOV?????EAX,DWORD?PTR?SS:[ESP+4]????;這段程序從這里開始,獲取一個表面的指針,作上記號GetSurfacePtr
??0043C8C4????????????2D?11270000?????SUB?????EAX,2711
??...
??0043C8DF????????????C2?0400?????????RETN????4
??0043C8E2????????????8B41?04?????????MOV?????EAX,DWORD?PTR?DS:[ECX+4]
??0043C8E5????????????C2?0400?????????RETN????4???????????????????????????;從這里返回,返回的指針就是主表面的指針
??
??取消硬件斷點,查找所有調用GetSurfacePtr的地方,在所有參考下斷點,運行幾次后來到:
??
??00408B94????????????E8?273D0300?????CALL????<swd3_ar.GetSurfacePtr>
??00408B99????????????8B0D?646E4C00???MOV?????ECX,DWORD?PTR?DS:[4C6E64]
??00408B9F????????????8B10????????????MOV?????EDX,DWORD?PTR?DS:[EAX]
??00408BA1????????????6A?00???????????PUSH????0?????????????????????????????;?在這里開始打補丁,5DE000
??00408BA3????????????68?00000001?????PUSH????1000000???????????????????????;?DDBLT_WAIT
??00408BA8????????????6A?00???????????PUSH????0?????????????????????????????;?SrcRect
??00408BAA????????????51??????????????PUSH????ECX???????????????????????????;?lpSrcSurface
??00408BAB????????????6A?00???????????PUSH????0?????????????????????????????;?DestRect
??00408BAD????????????50??????????????PUSH????EAX???????????????????????????;?lpDestSurface
??00408BAE????????????FF52?14?????????CALL????DWORD?PTR?DS:[EDX+14]?????????;?<DDRAW.DD_Surface_Blt(x,x,x,x,x,x)>
??00408BB1????????????C3??????????????RETN
??
??這里就是向主表面繪圖的代碼了,要在調用Blt函數之前把SrcSurface轉換成32位的Surface。
??首先要寫一個轉換的函數,并導入到主程序的輸入表,方便后面調用。
??
??005DE000????????????60??????????????PUSHAD
??005DE001????????????51??????????????PUSH????ECX
??005DE002????????????FF15?98D15D00???CALL????DWORD?PTR?DS:[<ConvertSurface>;?Swd3e.ConvertSurface
??005DE008????????????61??????????????POPAD
??005DE009????????????6A?00???????????PUSH????0
??005DE00B????????????68?00000001?????PUSH????1000000
??005DE010????????????6A?00???????????PUSH????0
??005DE012??????????-?E9?93ABE2FF?????JMP?????swd3_ar.00408BAA??????????????;?跳回去
??
??運行看一下:
??
??主要的顏色對了,但是圖像大小還不正確,原因是Blt函數的第二個參數DestRect是0,所以顯示到整個屏幕上去了,應該把這個參數設成窗口大小。需要在程序一開始時先保存一下窗口大小,在游戲一開始選擇對話框返回之后保存。查找DialogBoxParamA,下斷點:
??
??0040A66C????????????50??????????????PUSH????EAX
??0040A66D????????????FF15?9CA14A00???CALL????DWORD?PTR?DS:[<&USER32.Dialog>;?游戲一開始的對話框,在這里下斷點
??0040A673????????????48??????????????DEC?????EAX???????????????????????????;?返回之后馬上設置窗口位置并保存,5DE080
??0040A674????????????74?2E???????????JE??????SHORT?swd3_ar.0040A6A4
??0040A676????????????48??????????????DEC?????EAX
??0040A677????????????74?21???????????JE??????SHORT?swd3_ar.0040A69A
??0040A679????????????83E8?04?????????SUB?????EAX,4
??
??005DE080????????????60??????????????PUSHAD
??005DE081????????????A1?44634E00?????MOV?????EAX,DWORD?PTR?DS:[4E6344]????????????;?4E6344保存著窗口的名柄
??005DE086????????????50??????????????PUSH????EAX
??005DE087????????????FF15?4CD15D00???CALL????DWORD?PTR?DS:[<CenterWindow>]????????;?使窗口位置居中,內含保存窗口位置
??005DE08D????????????61??????????????POPAD
??005DE08E????????????48??????????????DEC?????EAX
??005DE08F??????????-?0F84?0FC6E2FF???JE??????swd3_ar.0040A6A4
??005DE095????????????48??????????????DEC?????EAX
??005DE096??????????-?0F84?FEC5E2FF???JE??????swd3_ar.0040A69A
??005DE09C????????????83E8?04?????????SUB?????EAX,4
??005DE09F??????????-?0F85?ABC3E2FF???JNZ?????swd3_ar.0040A450
??005DE0A5??????????-?E9?D8C5E2FF?????JMP?????swd3_ar.0040A682
??
??把上面5DE000作一下修改:
??
??005DE000????????????60??????????????PUSHAD
??005DE001????????????51??????????????PUSH????ECX
??005DE002????????????FF15?58D15D00???CALL????DWORD?PTR?DS:[<ConvertSurface>]??????;?Swd3e.ConvertSurface
??005DE008????????????61??????????????POPAD
??005DE009????????????6A?00???????????PUSH????0
??005DE00B????????????68?00000001?????PUSH????1000000
??005DE010????????????6A?00???????????PUSH????0
??005DE012????????????51??????????????PUSH????ECX
??005DE013????????????891D?D0DF5F00???MOV?????DWORD?PTR?DS:[<varSurfConv>],EBX
??005DE019????????????8B1D?4CD15D00???MOV?????EBX,DWORD?PTR?DS:[<rcWindow>]????????;?Swd3e.rcWindow
??005DE01F????????????53??????????????PUSH????EBX
??005DE020????????????8B1D?D0DF5F00???MOV?????EBX,DWORD?PTR?DS:[<varSurfConv>]
??005DE026????????????50??????????????PUSH????EAX
??005DE027????????????FF52?14?????????CALL????DWORD?PTR?DS:[EDX+14]
??005DE02A??????????-?E9?82ABE2FF?????JMP?????swd3_win.00408BB1
??
??一不小心點到窗口外面了,再恢復時怎么窗口位置又回去了?這個就比較簡單了,查找SetWindowPos函數,改成我們自己寫的CenterWindow函數就可以了,這個函數在40AF6A處,這里不再詳述。
??再運行一下:
??
??差不多快好了,但是中間怎么是花的呢?原來這些地方都是半透明的,程序中Alpha處理函數是按16位處理的,現在變成32位的,沒有進行修改。Alpha處理要針對每一個點的RGB進行處理,一般會調用GetPixelFormat函數,在這個地方:
??
??00427253????????????C74424?1C?20000>MOV?????DWORD?PTR?SS:[ESP+1C],20
??0042725B????????????C74424?20?40000>MOV?????DWORD?PTR?SS:[ESP+20],40
??00427263????????????FF51?54?????????CALL????DWORD?PTR?DS:[ECX+54]????????????????;?GetPixelFormat
??00427266????????????8B6C24?2C???????MOV?????EBP,DWORD?PTR?SS:[ESP+2C]????????????;?藍色掩碼
??0042726A????????????8B5C24?28???????MOV?????EBX,DWORD?PTR?SS:[ESP+28]????????????;?綠色掩碼
??0042726E????????????8B7424?24???????MOV?????ESI,DWORD?PTR?SS:[ESP+24]????????????;?紅色掩碼
??00427272????????????EB?1B???????????JMP?????SHORT?swd3_ar.0042728F???????????????;?這里NOP掉
??00427274????????????BE?007C0000?????MOV?????ESI,7C00
??00427279????????????BB?E0030000?????MOV?????EBX,3E0
??0042727E????????????BD?1F000000?????MOV?????EBP,1F
??
??上面取得RGB的掩碼之后判斷16位色下RGB各自的位數并作處理,16位色分555,565,556等多種模式,都統一成555來處理,由于改成32位色了,所以RGB的掩碼都不對了。把427272處NOP掉,默認為555色進行處理。
??再看一下:
??
??終于顏色都正常了。隨便讀一個檔開始游戲吧,結果一讀進去怎么又花了?原來大地圖和相聚檔時的轉換色深不在一個地方啊!按上面同樣方面修改,一共要修改大地圖,系統設置界面,物品買賣,戰斗等幾處。
??修改完成之后重新進行吧,發現所有字符都變成只有一半了:
??
??字符顯示一般會用到TextOut函數,在這個函數處下斷點,被斷下之后,發現是從439DB0處開始的,這個函數的作用是在一個離屏表面上繪制一個字符。這個表面是在439D2E處創建的,大小是64X64像素:
??
??00439D2C??????????8B0E????????????MOV?????ECX,DWORD?PTR?DS:[ESI]
??00439D2E??????????E8?FD280000?????CALL????<swd3_Ful.CreatOffScreenSurface(w>;?顯示一個字符用的臨時Surface
??00439D33??????????8B0E????????????MOV?????ECX,DWORD?PTR?DS:[ESI]
??
??往下走,來到:
??
??00439D68????????????FF52?58?????????CALL????DWORD?PTR?DS:[EDX+58]????????????????;?<DDRAW.DD_Surface_GetSurfaceDesc4(x,x)>
??00439D6B????????????8B4424?18???????MOV?????EAX,DWORD?PTR?SS:[ESP+18]????????????;?一行的字節數
??00439D6F????????????8B5424?10???????MOV?????EDX,DWORD?PTR?SS:[ESP+10]
??00439D73????????????D1F8????????????SAR?????EAX,1????????????????????????????????;?16位頁面右移一位變成一行的點數,32位要右移兩位
??00439D75????????????8996?DC0F0000???MOV?????DWORD?PTR?DS:[ESI+FDC],EDX
??
??從TextOutA函數往下找,來到:
??
??0043B3B9????????????8BCE????????????MOV?????ECX,ESI
??0043B3BB????????????E8?F0E9FFFF?????CALL????<swd3_ar.PrintChar>
??0043B3C0????????????8BCE????????????MOV?????ECX,ESI
??0043B3C2????????????E8?49FFFFFF?????CALL????swd3_ar.0043B310?????????????????????;?F7跟進
??
??...
??0043B31C????????????896C24?08???????MOV?????DWORD?PTR?SS:[ESP+8],EBP
??0043B320????????????50??????????????PUSH????EAX
??0043B321????????????E8?0AC4FDFF?????CALL????swd3_ar.00417730?????????????????????;?F7跟進后發現此函數是取得一個表面的數據指針
??0043B326????????????894424?10???????MOV?????DWORD?PTR?SS:[ESP+10],EAX
??0043B32A????????????8B83?D40F0000???MOV?????EAX,DWORD?PTR?DS:[EBX+FD4]
??
??在43B321處取得TextOutA寫入的字符表面的數據地址,下面就要對字符的數據進行處理了。在頁面創建和顯示字符時都是32位的,下面處理是16位的,要先把這個字符的表面改成16位的,補丁打在5DE380處:
??
??005DE380????????????E8?AB93E3FF?????CALL????<swd3_ar.GetSurfaceBuffer>
??005DE385????????????60??????????????PUSHAD
??005DE386????????????6A?40???????????PUSH????40
??005DE388????????????6A?40???????????PUSH????40
??005DE38A????????????50??????????????PUSH????EAX
??005DE38B????????????FF15?60D15D00???CALL????DWORD?PTR?DS:[<ButterTo16>]??????????;?Swd3e.BufferTo16,把32位的Surface數據轉換成16位的
??005DE391????????????61??????????????POPAD
??005DE392??????????-?E9?8FCFE5FF?????JMP?????swd3_ar.0043B326
??005DE397????????????90??????????????NOP
??
??這下字符顯示正常了。玩了一段時間之后,發現進系統界面的物品欄時,成了這個鬼樣子:
??
??
??字符的樣子正常,高度和Y坐標都變成了原來的一半,應該是向主背景頁面寫的時候出了問題。
??上面一開始創建主頁完成之后,馬上就會創建一個640X480大小的離屏背景頁面,很容易找到它的數據指針保存在4EE564處(作個記號為BackBuffer)。先在TextOutA處下斷點,斷下之后往下走,注意觀察信息窗口有沒有顯示BackBuffer的地址,一直來到這里:
??
??0043B899????????????8B4C24?28???????MOV?????ECX,DWORD?PTR?SS:[ESP+28]
??0043B89D????????????52??????????????PUSH????EDX??????????????????????????????????;?Y坐標
??0043B89E????????????8D042F??????????LEA?????EAX,DWORD?PTR?DS:[EDI+EBP]
??0043B8A1????????????53??????????????PUSH????EBX??????????????????????????????????;?X坐標
??0043B8A2????????????50??????????????PUSH????EAX
??0043B8A3????????????51??????????????PUSH????ECX??????????????????????????????????;?離屏頁面數據地址,4EE564處的值
??0043B8A4????????????8BCE????????????MOV?????ECX,ESI
??0043B8A6????????????E8?A5EFFFFF?????CALL????swd3_ar.0043A850?????????????????????;?F7跟進,往下走,注意信息窗口
??
??F7跟進之后往下走,注意信息窗口出現離屏頁面的數據地址,來到:
??
??0043A931????????????8B56?14?????????MOV?????EDX,DWORD?PTR?DS:[ESI+14]
??0043A934????????????8B4424?20???????MOV?????EAX,DWORD?PTR?SS:[ESP+20]
??0043A938????????????33DB????????????XOR?????EBX,EBX
??0043A93A????????????8B1402??????????MOV?????EDX,DWORD?PTR?DS:[EDX+EAX]
??0043A93D????????????8B4424?30???????MOV?????EAX,DWORD?PTR?SS:[ESP+30]????????????;?取到離屏頁面的起始地址
??0043A941????????????03D1????????????ADD?????EDX,ECX??????????????????????????????;?加上X坐標
??0043A943????????????8D3450??????????LEA?????ESI,DWORD?PTR?DS:[EAX+EDX*2]?????????;?目標點位置
??0043A946????????????8B4424?40???????MOV?????EAX,DWORD?PTR?SS:[ESP+40]
??
??在43A943處取得地址,是要往頁面上寫字符的點了。但是由于每個字符都要跑過這里一遍,不方便下斷點,所以想了一個笨辦法,打個補丁寫到一個文件里面。最終發現位置出錯時,在43A943處的EDX值不對,進一步跟蹤發現正常時43A931處取得的EDX指向的值都是500,出錯時變成了280,在這里打一個補丁,修正一下這個值,這里就不貼出代碼了。
??顯示正常字符時也會調用這里,所以還要設一個標志,從這個函數返回幾次之后可以來到:
??
??0044FEEA????????????B9?50634E00?????MOV?????ECX,swd3_ar.004E6350
??0044FEEF????????????E8?ACB6FEFF?????CALL????<swd3_ar.ShowString_Buf>?????????????;?在指定位置顯示一個字符串
??0044FEF4????????????46??????????????INC?????ESI
??
??在44FEEF處調用前設置一個標志,調用完之后改回來,可以解決字符位置不對的問題。物品,裝備,奇術,符鬼等界面在大地圖上對話之后字符位置不對的地方都用此方法修改。涉及到的顯示字符的函數除了上面43A850處外,還有43AB00和43AEE0兩處,也用同樣方法修改。
??上面修改完之后,基本不影響正常游戲了,但是顯示ANI動畫時還是會花屏,這同樣是由于頁面沒有轉換的原因,如下圖:
??
??
??先運行游戲,在顯示ANI動畫前對CreateFileA下斷點,直到堆棧中顯示ANI文件名,取消斷點。對BackBuffer的第一個字下硬件寫入斷點,運行后來到:
??
??00415DFA????????????8B15?702A4D00???MOV?????EDX,DWORD?PTR?DS:[4D2A70]
??00415E00????????????33C9????????????XOR?????ECX,ECX
??00415E02????????????8A0E????????????MOV?????CL,BYTE?PTR?DS:[ESI]?????????????????;?每次取一個字節
??00415E04????????????83C0?02?????????ADD?????EAX,2????????????????????????????????;?要寫入的目標地址
??00415E07????????????46??????????????INC?????ESI??????????????????????????????????;?源加1
??00415E08????????????4F??????????????DEC?????EDI??????????????????????????????????;?所有的數據數
??00415E09????????????66:8B0C4A???????MOV?????CX,WORD?PTR?DS:[EDX+ECX*2]
??00415E0D????????????66:8948?FE??????MOV?????WORD?PTR?DS:[EAX-2],CX???????????????;?寫到目標地址里面
??00415E11??????????^?75?E7???????????JNZ?????SHORT?swd3_ar.00415DFA
??
??從上面看到,這里寫到BackBuffer里面是連續的,而顯示到屏幕上的頁面應該是一行一行的,所以要進行相應的轉換,在函數返回前415E23處進行轉換,具體代碼就不貼了。
??更改之后發現畫面成了這個樣子:
??
??
??圖像大小對了,但是好像背景不正確,這是由于ANI動畫的每一幀不是完全重畫,只是重畫有圖像變化的部分,所以要在上面那個函數的一開始時先恢復前一幀的圖像。上面那一個函數從415D40處開始,在這里打補丁:
??
??005DE240????????????60??????????????PUSHAD
??005DE241????????????B9?00B00400?????MOV?????ECX,4B000????????????????????????????;?頁面大小
??005DE246????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[4EE564]????????????;?BackBuffer
??005DE24C????????????A1?88D15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpTemp>]??????????;?在ConvertANISurface里面保存的每一幀圖像
??005DE251????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE253????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>;?前一幀圖像恢復到BackBuffer里面
??005DE255????????????61??????????????POPAD
??005DE256????????????51??????????????PUSH????ECX
??005DE257????????????8B0D?941E4B00???MOV?????ECX,DWORD?PTR?DS:[4B1E94]
??005DE25D????????????53??????????????PUSH????EBX
??005DE25E????????????55??????????????PUSH????EBP
??005DE25F????????????56??????????????PUSH????ESI
??005DE260????????????57??????????????PUSH????EDI
??005DE261??????????-?E9?E57AE3FF?????JMP?????swd3_ar.00415D4B
??
??這下ANI顯示正常了,但是ANI里面有對話時又成了這樣:
??
??
??從上面的函數返回兩次之后,發現是從413137處調用的,ANI中出現對話之后在這里下斷,中斷后F7跟進,來到:
??
??00415A2E????????????57??????????????PUSH????EDI
??00415A2F????????????0F84?FF020000???JE??????swd3_ar.00415D34?????????????????????;?直接返回
??00415A35????????????392D?18724C00???CMP?????DWORD?PTR?DS:[4C7218],EBP
??00415A3B????????????0F85?B7020000???JNZ?????swd3_ar.00415CF8?????????????????????;?對話時從這里跳走
??
??00415CF8????????????A1?20294D00?????MOV?????EAX,DWORD?PTR?DS:[<Ani_Talk_Flag>]???;?是否已經保存過對話時的背景,第一次對話時要保存
??00415CFD????????????B9?00580200?????MOV?????ECX,25800????????????????????????????;?大小
??00415D02????????????3BC5????????????CMP?????EAX,EBP
??00415D04????????????75?20???????????JNZ?????SHORT?swd3_ar.00415D26???????????????;?第一次進入對話時不跳
??00415D06????????????8B35?64E54E00???MOV?????ESI,DWORD?PTR?DS:[<BackBuffer>]??????;?第一次對話時保存背景頁面
??00415D0C????????????8B3D?AC1D4D00???MOV?????EDI,DWORD?PTR?DS:[<Ani_Temp_Mem>]
??00415D12????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>
??....
??00415D26????????????8B35?AC1D4D00???MOV?????ESI,DWORD?PTR?DS:[<Ani_Temp_Mem>]????;?不是第一次進入對話就恢復
??00415D2C????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[<BackBuffer>]
??00415D32????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS>
??
??上面保存應該是轉換ANI背景之后的頁面,所以保存的地方需要修改:
??
??005DE200????????????60??????????????PUSHAD
??005DE201????????????A1?8CD15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpSurf_Temp32>]
??005DE206????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE208????????????8B3D?AC1D4D00???MOV?????EDI,DWORD?PTR?DS:[<ANI_Mem>]
??005DE20E????????????B9?00B00400?????MOV?????ECX,4B000?????????????????????????????????????;32位的頁面,要增大一倍
??005DE213????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS:[ESI]
??005DE215????????????A1?8CD15D00?????MOV?????EAX,DWORD?PTR?DS:[<lpSurf_Temp32>]
??005DE21A????????????8B30????????????MOV?????ESI,DWORD?PTR?DS:[EAX]
??005DE21C????????????8B3D?64E54E00???MOV?????EDI,DWORD?PTR?DS:[<BackBuffer>]
??005DE222????????????B9?00B00400?????MOV?????ECX,4B000
??005DE227????????????F3:A5???????????REP?????MOVS?DWORD?PTR?ES:[EDI],DWORD?PTR?DS:[ESI]????;也要同時傳到BackBuffer里面
??005DE229????????????61??????????????POPAD
??005DE22A??????????-?E9?E57AE3FF?????JMP?????swd3_win.00415D14
??
??注意由于頁面變成32位的,大小增加了一倍,所以把25800改成了4B000,前面415CFD處的25800也要改成4B000。這時要注意分配的內存也要增加一倍才行,往上面找到分配內存的地方直接修改即可(42EEC6和42EED5)。
??快完成了!這時全屏Alpha的地方只有一半了,如下圖:
??
??
??這個直接搜索push?4B000,改為96000即可。改了之后發現455124,455134,4527AB這幾處不能改,會跳出,再改回來即可。
??同樣戰斗時上半部分淡入淡出,搜索push?3C000,改為push?78000。
??其它幾個小修改:
??買賣東西時下半部分是花屏的:
??No.1
??4550E7,4550F1處96000改為12C000,分配內存
??No.2
??45510C,45514B,456287處25800改為4B000,拷貝內存
??No.3
??455124,455134處4B000改為96000,Alpha混合
??
??存檔時的縮略圖:
??0040E41F??????????^\75?F1???????????JNZ?????SHORT?swd3_win.0040E412
??0040E421????????????05?000F0000?????ADD?????EAX,0F00????????;改為2300
??0040E426????????????4E??????????????DEC?????ESI
??
??按P鍵時保存圖片,不影響游戲正常進行,我用了一個笨辦法,自己重新寫了一個保護圖片的函數,后來想可以直接修改程序里面原來的函數的,不想再弄了。
??
??到此基本結束收工,順便把免CD做了吧。一共要修改下面幾處:
??檢查光盤卷標,412023處:
??JNZ?????SHORT?swd3_win.00412038?????;改為JMP
??地圖數據從硬盤讀:
??0042A877???????????|68?60234D00?????PUSH????swd3_win.004D2360
??0042A87C???????????|68?A8214B00?????PUSH????swd3_win.004B21A8???????????;?ASCII?"%sswd3e\%s"
??改為:
??0042A877????????????68?B4364C00?????PUSH????swd3_win.004C36B4???????????;EXE根目錄
??0042A87C????????????68?98114B00?????PUSH????swd3_win.004B1198???????????;?ASCII?"%s%s"
??
??ANI動畫從硬盤讀:
??ANI動畫從硬盤讀:
??No.1
??0042ED8C???????????|68?60234D00?????PUSH????swd3_win.004D2360
??改為:
??0042ED8C????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??No.2
??0042ED98????????????68?00284B00?????PUSH????swd3_win.004B2800???????????;?ASCII?"swd3e\Video\"
??改為:
??0042ED98????????????68?06284B00?????PUSH????swd3_win.004B2806???????????;?ASCII?"Video\"
??No.3:
??0042EDA8????????????8803????????????MOV?????BYTE?PTR?DS:[EBX],AL????????;把盤符換成光驅的盤符,直接NOP掉
??
??開始游戲時從硬盤讀地圖:
??004336D7????????????68?60234D00?????PUSH????swd3_win.004D2360
??004336DC????????????68?A8214B00?????PUSH????swd3_win.004B21A8?????????????????????????;?ASCII?"%sswd3e\%s"
??改為:
??004336D7????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??004336DC????????????68?98114B00?????PUSH????swd3_win.004B1198?????????????????????????;?ASCII?"%s%s"
??
??BIK文件從硬盤讀取:
??No.1
??0049C789????????????68?60234D00?????PUSH????swd3_win.004D2360
??改為:
??0049C789????????????68?B4364C00?????PUSH????OFFSET?<swd3_win.Swd3eDir>
??No.2
??0049C795????????????68?00284B00?????PUSH????swd3_win.004B2800???????????????????????;?ASCII?"swd3e\Video\"
??改為:
??0049C795????????????68?06284B00?????PUSH????swd3_win.004B2806???????????????????????;?ASCII?"Video\"
??No.3直接NOP掉,替換盤符
??0049C7A5????????????884D?00?????????MOV?????BYTE?PTR?SS:[EBP],CL
??
??
??最后,附上SWD3E.DLL中幾個用到的函數說明:
??1.SaveBitmap32,把一個32位的頁面保存成位圖
??2.CenterWindow,主窗口居中顯示,同時把窗口位置保存在rcWindow中,并且會限制鼠標只能在游戲窗口中移動
??3.rcWindow,保存窗口位置,方便向窗口傳送圖像時使用
??4.ConvertSurface,把一個16位的頁面轉換成32位,要求原來的16位頁面是按行顯示的
??5.ConvertANIBuf,把ANI動畫的頁面轉換成按行顯示的頁面,供ConvertSurface使用
??6.BufferTo16,把一個32位的頁面轉換成16位的頁面,主要在顯示字符時使用
??7.PrintText,在一個頁面指定位置處顯示字符串,調試時使用
??8.DebugMsg,向Debug.txt文件中輸出調試信息
??9.lpTemp,ANI動畫時保存每幀原始數據,供下一幀恢復數據時使用
??10.lpTemp32,ANI動畫時保存轉換完成的數據,供ANI中的對話時恢復背景使用
??
??附上修改后的EXE文件和SWD3E.DLL文件。
??附件的EXE還有一個BUG,戰斗時敵人死亡時有時會跳出,三個以上敵人,最下面一個死去之后四面散開時(不是向左散開),會出現內存寫入錯誤。還沒有搞明白怎么回事,所以還沒有改。
2009-10-08解決此BUG,四面散開時散點的Y坐標會大于窗口高度,由于原來是全屏,所以窗口高度就是屏幕高度,現在改成窗口了,這里的最大值只能到窗口高度.
解決辦法:搜索常量0B54,把所有涉及到比較的地方都改成與1E0相比較,共有439103,4393C6,4394B1,439622,4396BF,439746,4397A7共七處.
同時把原來比較難看的宋體字改成比較好看的字體了.
??免CD之后的Huge.lmf文件要放在游戲根目錄下,BIK和ANI動畫要放在Video文件夾下!
??另外,還放了一個小小的彩蛋啦,不影響游戲畫面,這里就賣個關子啰!
??
--------------------------------------------------------------------------------
【經驗總結】
??由于DDRAW.DLL的導出函數很少,一開始不知道從何下手。某年月日突然用IDA把DDRAW.DLL打開了,一打開就提示我是否到
??MS$的網站上去下載符號表,這一下就發現快了很多。看來MS$有時還是很對得起勞苦大眾啊!
??幾個難點:
??1.字符顯示,找了好久才搞明白
??2.Alpha混色,一開始是想找到對應的函數進行修改,搞了好久發現太慢,突然來了靈感,改成用現在方法,果然有效
??3.字符位置不對,想了N種辦法也沒找到是從哪里出的錯,只好用現在這樣打補丁了
??4.現在還有一個問題,播放BIK動畫時會出錯。無奈水平不夠,還一點頭緒也沒有,反正BIK動畫也不影響游戲體驗,就懶得
??管了,等以后水平提高了有精力再去搞吧。
??
??終于寫完了,太累了,收工!
總結
以上是生活随笔為你收集整理的让天之痕窗口化运行!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP解决http和https跨域,ph
- 下一篇: openssl版本信息和支持的命令