L ZZZZZZ RRRRR SSSSS L Z R R S L aaa Z aaa R R u u S L a Z a RRRRR u u SSSSS XX L aaaa Z aaaa R R u u S XXXX L a a Z a a R R u u S XXXXXX LLLLLLL aaaaa ZZZZZZZ aaaaa R R uuuuu SSSSSS XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXX XXXXXX XXXX proudly presents his 36.Cracking Tutorial (29.01.2000) XX Cracking BitArts Fusion 1.0 I. Introduction I.1 The tools II. The essay II.1 First look at the target II.2 The serial II.3 The keygen III. BTW I. Introduction Greetings dear reader. The program this tut deals with is the AOTW (App of the week) in my beloved #Efnet chan #cracking4newbies. It was said that it has a very good protection with Anti-Everything code and additional stuff that makes cracking harder. Especially the ANTI-SICE code is most interesting because neither FrogSice nor Stone's WinIce detector code know/show this way. I.1 The tools SoftIce (I have 3.25) Turbo Debugger or TRW2000 Interrupter 1.02 HexWorkshop (I have 3.0) The Customizer FileMon and RegMon A PE analyzer (I use my own one, but you should get a good one) Good music: I listened all the time to the song "Nachtgeburt" by "Eisregen" - German Death Metal r0x =) II. The essay The program we deal with is an interesting program if you want to distribute programs that require many DLL or OCX files. It just links them all to the EXE file and unlinks them during runtime. Additionaly it compresses the file and adds the same kind of SICE detection like the program itself uses. No surprise, though: The program is packed with itself. Finding the SICE checks in the EXE file: Alright. If you have SICE loaded when you start fusion.exe it will neither immediately exit nor throw out a message like "Debugger detected". In fact, it only crashes. So we need to trace right from the entry point and find where the debugger is detected. So, set a CCh at the entrypoint (Use Interrupter to achieve this). Interrupter tells you that it has replaced a 55h byte. Keep this in mind, because you have to change it back when you start the program. Now set a breakpoint on Interrupt 03 (bpint 03), so that SICE breaks at the CCh you added. When SICE breaks enter "e eip 55" and trace through the program. It will crash at :0068d187. The instruction here is "mov [eax], al" and eax is 00000000 - My first attempt was to figure out what eax should really be, so that "mov [eax], al" would work. That was quite useless and didn't get me too far. Now I tried another debugger (Turbo Debugger) and looked if it is also detected by the unpacking routine. It was not detected and this helped me quite much. When I looked at :0068d187 there was another instruction insted of "mov [eax], al". So, it seems that the result from the debugger check is used as a value to create some parts of the (minimal polymorphic) unpacking routine. Now I searched for the place where the registers have different values when I compare the SICE and Turbo Debugger (TD) values. After the call at :0068D107 ESI had the value 6 when SICE was loaded and 10h when SICE was not loaded. So, when I traced the over call I changed the value of ESI to 10h (r esi 10) and everything worked: Better, the next few lines where created correct and the program crashed few lines later. The same procedure again: Trace over the calls with TD and SICE and look where the values of the registers differ. This happens next time when you trace over the call :0068D203. But here not only one register value differs, but several. So I traced into the call. If you already traced in the first call to find out how SICE was detected, you have seen that it works somehow like this: SIDT - Save Interrupt Description Table Do some stuff SIDT again sub first_SIDT, second_SIDT if result is 06: SICE detected if result is 10: SICE not detected That might be the reason why someone said that the prog has Anti-FrogSice code. But this is not true, FrogSice just does not know this kind of detection. Back to our call: If you trace into it you will see nearly the same as in the first call. A SIDT and then some stuff and then the important "sub esi, ebx" at :0068D8A5. Here is the next check. If you traced over this line just change the value of esi to 10 (r esi 10) again. Now you have two choices: Trace the EXE for some minutes or just believe me that this was the last debugger check inside the EXE and press CTRL-D to run the prog. The EXE will load normal. What's that you say? It still crashes? Yeah, true, but the reason is not the EXE file. It loads normal as you can see when you set a bpx on "GetCommandLineA". The reason is the file SOFLOCX4.OCX which can be found in your system directory. As far as I know Softlocx is a software wrapper just like SalesAgent or VBox which should protect shareware. In fact, it is used to calculate the serial and to show the nagscreen. But why does it crash? Simple. It is also packed with the same packer as the EXE file and so it detects SICE in the same way and crashes in the same way. Finding the SICE checks in the OCX file: As a OCX file is - just like a EXE or DLL - a standard PE file it has an entrypoint where we could set a CCh to break on. If there was no entrypoint, how should the OCX be unpacked anyway? To set this CCh you can use Interrupter, again. Now restart the prog and be sure that you trace through the EXE file and always set ESI to 10 when SICE was detected. Also be sure to have set an "bpint 03" so that SICE breaks at the entrypoint of the OCX file. But this isn't enough. It will still crash. I was quite long thinking about the "Why?" although the solution is more than simple. What does the prog do? Wrap all needed OCX and DLL to a single EXE and unpacks all stuff during runtime? Exactly this is used here: The OCX is overwritten when the prog is run, so our CCh at the entry point is of no use. Then I remembered what I saw when I traced trough the program: A call to CompareFileTime. When I first saw it I thought it was kind of CRC check, but it is used to replace the OCX file when it had a "wrong" date (actually, it *is* a kind of CRC check ;). So, I set a bpx CompareFileTime, made sure that there was a CCh at the entrypoint of the OCX file and restarted the prog. Don't forget to change the values of ESI when SICE is detected. After the second SICE check in the EXE file, I hit CTRL-D to get out of SICE and it immediately brought me back inside the CompareFileTime routine. I hit F12 to get out of it and EAX was 1 --- snippet from my API reference --- Return Value If the function succeeds, the return value is one of the following values: Value Meaning -1 First file time is less than second file time. 0 First file time is equal to second file time. +1 First file time is greater than second file time. --- snippet from my API reference --- So, I had to change eax to 0 "r eax 0" and then I went out of SICE (CTRL-D). I was, once again, immediately back in SICE. This time the OCX was not replaced and SICE breaked at the CCh we set at the entry point. Enter "e eip 55" to remove the CCh again and then trace through the unpacking routine of the OCX file. Don't forget to bypass the SICE checks. I won't explain how this works this time, because it is 100% the same as in the EXE file. If you passed both SICE checks here, you can hit CTRL-D and the program will start, as if SICE would not be loaded. btw: At this time I was already debugging this program for 3 hours, drank several bottles of water and ate snacks that would be enough for watching 3 movies ;) A little RegMon/FileMon Intermezzo: When you use RegMon on the program you can easily find the registry key where the unlock key will be saved (encrypted). RegMon reveals this: 235 Original OpenKey HKCR\FusionV1 SUCCESS hKey: 0xC2A20B30 236 Original QueryValueEx HKCR\FusionV1\ NOTFOUND 237 Original CloseKey HKCR\FusionV1 SUCCESS When you use FileMon on the program I found something very interesting. FileMon reveals that the program tries to read data from a file called "fusion.net". So, I created one with my standard phrase "Trallala" in it and looked what happened. Wh00p, the nagscreen and the time limit was gone. I already though that I cracked it, but when you try to create a project, the crated EXE file will still have the limitations of an unregistered version. Getting a valid serial: Now, when the Nagscreen, where you could register the prog, appeared I had the next problem: Finding a working breakpoint as my beloved hmemcpy didn't work here. I was trying all kind of freaky functions to break on, before I tried GetWindowTextA. I always thought if GetWindowTextA works, hmemcpy would work, too, but this is not the case here. Whatever, the GetWindowTextA function SICE breaks on tries to fool you anyway. It gets the text of the Register-Button which is obviously not used to calculate the serial. You can see this if you look what value is pushed in front of the call and compare this with the handles of the edit field where you can enter the serial and with the handle of the button. Whatever, the correct calculation of the serial is quite close to this call. If you look few lines above you will see a call to GetWindowTextLength and a call following it. This call is used to calculate the correct serial. I will use the serial "12345678" as the eight digit unlock code and you should take the same. Trace one time over the call that calculates the serial and then do a "s 01000000 l 10000000 '12345678'" - SICE tells you where this string is found in memory. In my case at :01691DFC. Now I set a "bpm 01691DFC rw" so that SICE tells me when the first byte of my serial is either read or written. I hit CTRL-D until SICE breaks on memory access of my serial. This is at 1000B96C - This is the loop which calculates 4 of the 8 bytes of the unlock code: 1000B92F-1000B97E. When the serial is calculated at 1000B980 and 1000B983 two "dword ptr" values are pushed and then there is a call. When you do a "d @(ebp-1c)" you can see "1357". When you do a "d @(ebp-2c)" you can see four other chars which got calculated. For me this was: GU3I, but this will differ at your machine, because a "magic" value is created when you start the prog the first time and I believe that the serial is additionaly calculated by the reg code of your Win95/98... (no guarantee on this one, I just saw my license number quite often in the part of the memory where the serial is calcuted). With this new information my new serial is: G2U436I8 Now try to register again and when you are at 1000B980 trace with F8 into every call until you come to 1002C74B. Set a bpx here, because this is a very important instruction (cmp al, bl). If you can make SICE break here 4 times, you will have a valid registration number. BL will hold the char from your serial and compares them with AL which is calculated. Now you can start to bruteforce a little, because to make those two values be the same is not enough. I don't know where the last check sits, but this does not matter, because you can choose nearly everything for the first value. Try "A", "3", "4" at first. Most time it works. With this new information my new serial is: GAU436I8 Just go on like this: Mostly making al=bl in your serial works, but when it does not work just try 3 or 4 random chars. In this way I was getting the following correct serial: GAU231I5 - my "magic" number was 30583089. That's all job done. I cannot be bothered to write a keygen ;) III. BTW Greetings go to: +Sandman, Acid Burn, alpine, Blind Angel, Borna Janes, Carpathia, CrazyKnight, DEATH, DEZM, dimwitz, DnNuke, duelist, Eternal Bliss, Fravia+, Iczelion, Jordan, KnowledgeIsPower, Knotty, Kwazy Webbit, Lucifer48, MisterE, Neural Noise, noos, Prof.X, R!SC, rubor, Shadow, SiG, tC, The AntiXryst, The Hobgoblin, TORN@DO, ultraschall, viny, Volatility, wAj WarezPup, _y and all the guys I forget and I'll add next time. Comments: lazarus_hf@hotmail.com Visit hello.to/lazarus