######## Cdilla Safedisc Tutorial by Black Check ######### Intro ------- Well,since my first tut CDilla changed their shit a little.Time to be destructive again... After all CDilla was quite lazy.Our target is Soul Reaver-Legacy of Kain [German].Btw i assume you've already read my first tutorial.Let's do it then... Tools ------- -Soul Reaver original CD (this is just a tool,we don't need it later :-P ) -Softice -Adump 1.0 -Procdump 1.5 -Frogsice 0.31 -Hex Workshop 32 ##################### 1. Anti Sice # ##################### Hhmm..very disapointed about this.They didn't even try to improve their Sice detection.What's up with you guys?Maybe next time.So we'll use Frogsice 0.31 and everything is fine.. Even my old method of patching the exe and dplayerx.dll still works.(but isn't needed with new Frogsice)... ##################### 2. Let's dump # ##################### Well let's dump then... The entrypoint of the icd is 4c11e0. R!SC found a nice Breakpoint for dumping: bpx Freelibrary.Run Frogsice set your bpx and start Kain2.exe.Repeat F5,u 4c11e0 untill the code gets decrypted.Now F12 and assemle a jmp eip.Now F5 and make a full dump with Procdump (1.5!). We need a good rdata section so we'll make a partial dump,too.Now rip the rdata out of the partial dump (moved by 1800h bytes) and create rdata.dat. ###################### 3. Fixing the .rdata # ###################### At least they changed their ApiCall System a little.Though it's not that awesome,my old method won't work anymore. x: pushad push 00000000 | Function number push 00000000 | Dll number call[x+21] add esp,8 popad jmp[x+13] x+1b: dd ApiAddress (=f700c0) x+1f: dw ??? x+21: dd ApiFuckUpCallAddress x+25: pushad push 00000001 push 00000000 call[...] . . . In the older version the call returned the Addresses we needed in eax and ecx.That's a lame bug that has been fixed.The real Api Address is still copied to code seg.So we'll let it decrypt all calls,dump the whole code and code a little ApiFixup.We have 4ah Kernel and 20h User imports here. 3.1 Decrypting everything -------------------------- Start Adump now. Put a breakpoint on the the entrypoint and run.Now assemble: 4c11e0: push ebx | manualy set EBX to 0 !!! push 00000000 call f700c0 | the CDilla Apicall inc ebx cmp ebx,4a | number of Kernel imports jnz 4c11e0 jmp eip Let it run.Change the push to 1 and the cmp ebx to 20.Set ebx back to 0 and let it run again.Now all the Addresses are in the code. 3.2 Dumping the ApiCall code -------------------------------- First we need to find the beginning of this crap.Step into the first api call and scroll up.It looks like this: F94540: pushad push 0000000 push 0000000 | Kernel call [...] Write down the Address of the first pushad.You'll have to use the 'u xxx' command to get it displayed right. Now scroll down to the first User call: F95004: pushad push 00000000 push 00000001 | User call[...] Write down,too.Btw you can get the number of exports this way. Just scroll up a little and you'll see that at the last Kernel import 00000049 is pushed.Scroll down to the last User import and write down the Address where the zero bytes start. For some strange reason we need to dump this in two parts: m F94540 l ac4 828de000 m F95004 l 49f 828df000 (Adump mem) Write the files to disc and call them Kernel.dat and User.dat. 3.3 Our ApiCall Fixup ---------------------- Now let's code a little fixup that takes the right import addresses and puts them in our rdata dump.Cdillafx.exe takes three files: Kernel.dat User.dat Rdata.dat and generates Rdata.fix,which is a working rdata section.I coded this in about 15 minutes so you'll have to put some values there by hand... ################# CDillafx.c ################################ #include #include #include #include #include #include typedef unsigned char byte; typedef unsigned long u32; byte *Kernel,*User,*Rdata; u32 KernelOff=0xf94540; // we wrote this down before u32 UserOff =0xf95004; u32 Offset=0; u32 GoodAdr,BadAdr; int Temp,k=0,u=0; int KernelSize=2756; // size of our files int UserSize=1183; int RdataSize=14336; void Load_File(byte*File,byte*Buf,unsigned l) { int handle, bytes; if ( (handle=open(File, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1) { printf("Error opening file.. "); exit(1); } if (read(handle,Buf,l) == -1) { printf("Read failed.\n"); exit(1); } close(handle); } int Change_Entry(u32 Good,u32 Bad) { u32 Entry,o; for(o=0;o