Thorium 114 Share Posted April 23, 2014 (edited) A programing subforum and only one topic? And that topic isnt about Sacred? (even if it's very interessting) If there is any interest I could post some stuff about programing for Sacred, stuff that also could be applied to other games. What do I mean by that and who am I? I call myself Thorium on the internet and I am a hobby coder. Well I was, actualy I am a professional for 1,5 years now. However I dont work in the gaming industry. I was one of the cofounders of a coding crew called SacredVault. As the name sugests we developed stuff for Sacred, Sacred Underworld to be precise. So I am not a develeoper of the Sacred team and I dont want to write about how to develop games. I want to write about twiddleing with games as a coder. If you think about that the first thing that comes to mind are trainers and multiplayer cheat and cracks. Well SacredVault was not about that. It was about improving the game without making the original developers angry. ^^ So for the start I just want to post a source code which is open for quite some time now. Still you might not read it or even heard about it: The unofficial 2.29 patch for Sacred Underworld. So I just post the source and write some background infos about it later. If there is any interest. No point in writing if nobody cares to read. ^^ Also I have more stuff to share. Do you know there is a interface in Sacred Underworld to read out character infos? The Sacred developers build it in for us. I even have some cool stuff for Sacred 2. The patch is a ASM hack, so the source is pretty much a list of changes done to the disassembled code of Sacred.exe. I just translated the comments from german to english and found there is some code missing. And it's actualy a older source version. I cant find the "newest" build version, which would be 14. So there are actualy 2 bugs existing in build 12. Who ever finds them gets a cookie. ^^ /--------------------------------\| Inofficiel Patch 2.29 Build 12 |\--------------------------------/Stand: 29.01.2007 by Thorium (SacredVault)*********************************************** Change 1: ** removal of loading of the binary ressource ** and add loading of Global.res from HDD ***********************************************Starting at address 0080DC09 replace asm-code:------------------------------------------------;preserve registerspush ecxpush ebxpush esipush edimov edi,eax ;preserve pointer to Global.res path for later usemov ebx,ecx ;preserve pointer to pointer to Global.res for later use;install SEHpush -1push 00889257mov eax,dword ptr fs:[0]push eaxmov dword ptr fs:[0],esp;call CreateFile to open Global.respush 0 ;hTemplateFile (nothing)push 0 ;dwFlagsAndAttributes (nothing)push 3 ;dwCreationDisposition (OPEN_EXISTING)push 0 ;lpSecurityAttributes (nothing)push 0 ;dwShareMode (no sharing of the file)push 80000000 ;dwDesiredAccess (GENERIC_READ)push edi ;lpFileName (pointer to Global.res path)call [0088E244] ;Kernel32.CreateFilemov ebp,eax ;preserve file handle;check if file is opencmp eax,-1je 0080DC73 ;jump to error handling;get size of Global.respush 0 ;lpFileSizeHigh (nothing)push ebp ;hFile (file handle)call [0088E1D8] ;Kernel32.GetFileSizemov esi,eax ;preserve file size;check if file size could be readcmp eax,-1je 0080DC73 ;jump to error handling;check if file is big enough (it's damaged if smaller)cmp eax,4jb 0080DC73 ;jump to error handling;call Sacred-procedure to allocate a buffer for Global.respush esi ;nSize (size of buffer)call 008485E2 ;allocate buffermov [ebx],eax ;save buffer address to variable;load Global.res into the bufferpush 0 ;lpOverlapped (nothing)push edi ;lpNumberOfBytesRead (pointer to variable)push esi ;nNumberOfBytesToRead (size of Global.res)mov eax,[ebx] ;get memory address for Global.res into eaxpush eax ;lpBuffer (address of the Global.res buffer)push ebp ;hFile (file handle)call [0088E1D4] ;Kernel32.ReadFile;close Glboal.res filepush ebp ;hObject (file handle)call [0088E24C] ;Kernel32.CloseHandle;cleanup and returnmov al,1mov ecx,[esp+4]mov DWORD PTR FS:[0],ecxpop ebppop edipop esipop ebxadd esp,10ret 4;error handling on address 0080DC73;display MessageBoxpush 10 ;Style (MB_OK|MB_ICONHAND|MB_APPLMODAL)push 009E1128 ;Title (Sacred) text is allready therepush 0095CFBC ;Text (Error: Can't load Global.res!) Text must be replaced on that addresspush 0 ;hOwnercall [0088E34C] ;User32.MessageBoxA;terminate Sacredpush 0 ;ExitCodecall [0088E0EC] ;Kernel32.ExitProcess------------------------------------------------Now fill code with NOP's up to address 0080DCCB.And we now can remove binary ressource 107 to save 2MB .exe size.*********************************************** Change 2: ** Remove cheat codes secure and clean ** to get space for new code we want to write ***********************************************Starting at address 0061561B replace asm-code:Assures the cheat code will never be jumped to.------------------------------------------------NOPNOPNOPNOPNOPNOP------------------------------------------------Fill address space starting at 006156B8 up to 00615FA7 with NOP's.This address space can now be used for our own code.*********************************************** Change 3: ** Multi-Instancing ***********************************************Sorry, somehow this code got lost. Dont ask me how. It wasnt very interesting anyway. Just changed a conditional jump on the check of a global mutex.*********************************************** Change 4: ** Chat-Crash fix ***********************************************Starting at address 0084AE81 replace asm-code:------------------------------------------------jmp 006156DE ;jump to error checkingnop------------------------------------------------Starting at address 006156DE replace asm-code:------------------------------------------------;Instructions must be executed here, because we overwrote them in the original procedure.je 0084AEABmov edx,dword ptr ss:[esp+10] ;get pointer to the data into edx;preserve registerspush ecxpush edxpush ebxpush ebppush esipush edi;call IsBadReadPtr to check if memory region can be readpush ecx ;DataSizepush edx ;DataAddresscall [0088E240] ;Kernel32.IsBadReadPtr;restore registerspop edipop esipop ebppop ebxpop edxpop ecx;check if read is possiblecmp eax,0je 0084AE87 ;yes, return to original procedure;no, output debug message to Sacreds log filepush 0095CFF4 ;Msg (Sacred.exe Crash fixed!)call 0066F1C0 ;Sacred-Procedure: Debugoutputadd esp,4 ;cleanup stack;return to end of original procedurejmp 0084AEAB------------------------------------------------Starting at address 0095CFF4 replace text:------------------------------------------------Sacred.exe Crash fixed!------------------------------------------------And replace hex numbers:------------------------------------------------0A 00 00 00------------------------------------------------*********************************************** Change 5: ** change displayed version number ***********************************************First of all change version number in ressources.Now the version system is: Major.Minor.BuildThat means for this version: 2.29.12.0Now change version number on main menu screen:starting at address 00758ED0 replace asm-code:------------------------------------------------push 20push 0095D014------------------------------------------------Now write new version number as zero terminated string to address 0095D014.With that change Sacred will display a different version number than the internal version number. This makes it possible to still connect to the internet lobby and display a new version number.*********************************************** Change 6: ** Debuggerfreez-Fix ***********************************************Fix for freez if Sacred is started by a debugger.Starting at address 00810B0F replace asm-code:------------------------------------------------;remove forcing of window focusnopnop------------------------------------------------*********************************************** change 7: ** load Balance.bin by using hardcodes path ** implemented for VeteranMod, but never used ***********************************************Starting at address 00856A8A replace asm-code:------------------------------------------------jmp 00615717nop------------------------------------------------Starting at address 00615717 replace asm-code:------------------------------------------------;preserve registerspush ecxpush esipush edi;check if balance.bin is about to get loadedmov esi,dword ptr ss:[esp+10] ;get address of file path from stackmov edi,0094C4D4 ;address of compare stringmov ecx,4cldrepe cmpsdjne 00615736;force use of hardcoded file pathmov ecx,009E1AFCmov dword ptr ss:[esp+10],ecx;00615736;restore registerspop edipop esipop ecx;instructions must be executed here, because we overwrote them in the original procedurepush ebpmov ebp,espsub esp,1C;return to original procedurejmp 00856A90------------------------------------------------Starting at address 0094C4D4 replace text:------------------------------------------------.\Bin\Balance.bin------------------------------------------------ Edited April 23, 2014 by Thorium 1 Link to comment
SX255 630 Share Posted April 23, 2014 By any chance, do you know of a Sound.pak Unpacker/Repacker? I can unpack the data, but have no way to put it back into Sound.pak Link to comment
Thorium 114 Author Share Posted April 23, 2014 By any chance, do you know of a Sound.pak Unpacker/Repacker? I can unpack the data, but have no way to put it back into Sound.pak No. The only person I know of who could have a packer would be SonicMouse. Maybe you can find him. After Sacred I think he wend on hacking MapleStory. I know he did wrote unpacker for most of the .pak's. Also he wrote tools he didnt released. If you can code here are some infos: http://wiki.xentax.com/index.php?title=Sacred#Format_Specifications_2 If the files are compressed, it should be ZLib. Link to comment
Thorium 114 Author Share Posted April 24, 2014 (edited) Let's talk about how to make a unofficial patch. First of all there are 3 different ways to alter the game code: 1.) You edit game scripts. I dont talk about that here. 2.) You hook procedures of API's to manipulate parameters and return values. This is actualy very powerfull and often used by unofficial patches. 3.) You can change the actual executable code of the game to do whatever you want. I want to focus on that in this post. I will not go terribly deep into it, just give you some directions so you get some ideas. First of all, if you dont know assembler language: learn it! You might have heard that assembler is very complicated and hard to learn. This is totaly false! In fact assembler is very simple and very easy to learn. We dont use high level languages because assembler is so complicated. We use them because coding in assembler is a lot more work and your code is platform dependent. There are many tutorials about assembler. Go and learn it! In case you dont know what assembler language is: It's a way of programming on which you directly program the CPU. Every command you write is one command the CPU understands and executes without the need for a compiler, which breaks commands down into smaler commands the CPU understands. That CPU commands are called: Instructions. So you work at the lowest possible level. There is only one level lower: machine code. But assembler code is just a human readable representation of machine code, so I dont realy count machine code as lower. Every program is made of machine code (with some exceptions like Java). Typicly programs are written in high level languages and are translated into machine code by a program called: compiler. Basicly the compiler takes a high level command (such as a command to output text to a window) and breaks it down into machine code instructions, so the CPU can actualy execute the program. This is important to understand because you can actualy look at the machine code of a compiled program, such as Sacred.exe. And even better you can translate it into a human readable form (assembler language) with a so called disassembler. There is also decompiling, which is the process of translating machine code back to high level language code. But better forget about it for now. There is no automatic working decompiler. The only decompilers that are working are interactive and using them requires quite some knowlege. Which you dont have right now, or you woudnt read this. ^^ However it's actualy pretty easy to translate machine code into assembler code with a disassembler. There is just one tiny little problem: Disassembled assembler code of a game such as Sacred is huge. And I mean realy huge, literally millions of instructions. And no meaningfull names for variables and procedures, just memory addresses. So your efforts to make a unofficial patch do not start at disassembling the .exe of the game. First you need to know about the bugs you want to fix or about the features you want to add. Take some time and think about if and how this could work. What do you need to change to get the result you want. This is the most important step. Because it will make the next step a lot easier and the next step is the hardest. Now, you know what you want to change. You have some ideas how this could work. Now you need to find the code you need to change. And thats the challenge. Once you found the code that relates to a bug it's easy to change the code or add some new code. The process of finding the code you want to change is called reverse engineering. Reverse engineering is the art of taking something apart to learn how it works. And thats what we do with the game we want to patch. However we dont start at the beginning of the disassembly and read all the millions instructions and try to understand the whole program. That would be way to much work. Instead we try to get as near to the code we search as possible befor starting to read the actual assembler code. Again that starts with thinking about the code you want to find. Think about how the code could work. What API procedures it could use. Does it access a file? Does it display something on the screen? Lets say it accesses a file. So you fire up your assembler level debugger. What? You dont have a assembler level debugger? Get one! I use OllyDbg. A debugger is basicly a tool that helps you find bugs in your software. A assembler level debugger helps you find bugs in any software but only operates on the assembler level. So you fire up your debugger and take a look at the imported WinAPI functions. You will find a function called CreateFile, thats a function for accessing files, not just for creating them. So you tell your debugger to stopp the program every time this procedure is been called. Thats called a break point. Start the program and as soon as the program accesses a file the debugger will show you the code that does access the file. Just skip until your desired file is accessed and you should be pretty near to the code you search. So thats just to give you some ideas and some keywords to google about. Changing the code is pretty easy in most cases. Finding it can be very challenging and there are a number of tools you can use for this, like Debuggers and memory scanners. But it still is the hardest part and it requires the most time. You might end up searching 10 hours for a one byte change. So making a unofficial patch is more about reverse engineering than it is about writing code. I hope that makes any sense to you, I will write more later. Edited April 24, 2014 by Thorium Link to comment
Dragon Brother 619 Share Posted April 24, 2014 This is a rather interesting read Thorium. Thanks for posting it here for us Link to comment
Saraphima 34 Share Posted April 25, 2014 That was a great read! Didn't understand it but still. I would like to say that if you make your own tools or whatever you should share them, people go poof and that kills off projects because they are the only owners of the tool that does whatever it does. Link to comment
Thorium 114 Author Share Posted April 25, 2014 (edited) I would like to say that if you make your own tools or whatever you should share them, people go poof and that kills off projects because they are the only owners of the tool that does whatever it does. Yes, we should do this. I do it. As SacredVault stopped, we released a lot of stuff that was not public befor. Mostly because it was unfinished other stuff because it could be used for cheating. For example our member Ufo wrote a excelent character editor for our testing. Which he did release after SacredVault went inactive. He is also the one that keeps the SacredVault website online, so there still is a source for our stuff. I did release unfinished modding tools we used to create the VeteranMod. There is a creature.pak editor, a balance.bin editor and a weapon.pak editor in addition text files with format specification and constant definitions. The creature.pak editor is the most complete and allows you to edit 70% of the values of every creature in Sacred Underworld. However this is all german only. I also released the source code for the inofficial patch 2.29 and the source code of the unfinished 2.30 patch. Another interessting source code is the Cheaters's Nightmare source code. A program that protects your Sacred Underworld Server by scanning for cheated items and allowing you to keep a blacklist of users with autokick function. This is all released for educational purposes and to inspire other people for new projects. As a coder you do take a lot of informations and even code from other people, so yes, you should give back. Edited April 25, 2014 by Thorium Link to comment
munk 26 Share Posted May 7, 2014 I learned a lot- compared to the little I knew before. Very interesting stuff. Link to comment