I did quite some research concerning this protection: I tried to unlock
the program by entering a serial, tried to crack the loader, tried to
unwrap, tried to make SoftWrap believe I just bought the program so it
would unlock.
Well, two attempts were successful: the cracking of the loader and the
unwrapping. Let's start with cracking the loader :-)
Part 1: Cracking the loader.
***********************
First important thing to tell about the loader is that all loaders for
any program are the same! That means that if you cracked one, you can
write a patcher to patch ALL of them :-) I found out by downloading SoftWrap
and wrapping Notepad. The instructions and locations were exactly the
same. So, in this example I used 2findmp3, but you can use any program
protected with it.
First thing you'll notice is the anti-softice. It's the typical "check-if-softice-files-are-there"
method with the CreateFileA API. So, by setting a breakpoint on this API,
you can find following code (it's pretty long, explanations are added
in blue):
Start partial code
0041573B _WinMain@16 proc near ; CODE XREF: start+C9p 0041573B 0041573B arg_0 = dword ptr 4 0041573B 0041573B call sub_409FCD <- Checks operating system to determine SICE/ NTSICE 00415740 cmp byte_42B67C, 1 00415747 mov eax, offset a_Ntice ; "\\\\.\\NTICE" 0041574C jz short loc_415753 0041574E mov eax, offset a_Sice ; "\\\\.\\SICE" 00415753 00415753 loc_415753: ; CODE XREF: _WinMain@16+11j 00415753 push ebx 00415754 push ebp 00415755 push esi 00415756 xor ebp, ebp 00415758 mov esi, ds:CreateFileA 0041575E push edi 0041575F mov ebx, 80h 00415764 push ebp 00415765 push ebx 00415766 push 3 00415768 push ebp 00415769 mov edi, 0C0000000h 0041576E push 3 00415770 push edi 00415771 push eax 00415772 call esi ; CreateFileA 00415774 cmp eax, 0FFFFFFFFh 00415777 mov dword_42B9BC, eax 0041577C jnz short loc_415789 <- If Softice file does not exist, don't jump 0041577E call ds:GetLastError <- Get the error, result in eax 00415784 cmp eax, 5 00415787 jnz short loc_4157A0 00415789 00415789 loc_415789: ; CODE XREF: _WinMain@16+41j 00415789 push dword_42B9BC 0041578F call ds:CloseHandle 00415795 push offset aSoftwrapCannot ; "Softwrap cannot be run with SoftIce loa"... 0041579A call sub_409964 0041579F pop ecx
....some code skipped....
00415818 loc_415818: ; CODE XREF: _WinMain@16+D6j 00415818 push ebp 00415819 push ebx 0041581A push 3 0041581C push ebp 0041581D push 3 0041581F push edi 00415820 push eax 00415821 call esi ; CreateFileA <- Same story as above 00415823 cmp eax, 0FFFFFFFFh 00415826 mov dword_42B9BC, eax 0041582B jnz short loc_415838 0041582D call ds:GetLastError 00415833 cmp eax, 5 00415836 jnz short loc_41584F 00415838 00415838 loc_415838: ; CODE XREF: _WinMain@16+F0j 00415838 push dword_42B9BC 0041583E call ds:CloseHandle 00415844 push offset aSoftwrapCannot ; "Softwrap cannot be run with SoftIce loa"... 00415849 call sub_409964 0041584E pop ecx 0041584F 0041584F loc_41584F: ; CODE XREF: _WinMain@16+FBj 0041584F push ebp 00415850 push ebp 00415851 push ebp 00415852 push ebp 00415853 push offset aErrorIn ; "Error in" 00415858 push offset dword_42C988 0041585D call sub_4099AE 00415862 add esp, 18h 00415865 push ebp 00415866 push ebx 00415867 push 3 00415869 push ebp 0041586A push 3 0041586C push edi 0041586D push offset a_Regmon ; "\\\\.\\REGMON" <- Hey cool! This prog checks regmon too ;) 00415872 call esi ; CreateFileA <- Same story as with the SoftICE check :) 00415874 cmp eax, 0FFFFFFFFh 00415877 mov dword_42C020, eax 0041587C jnz short loc_415889 0041587E call ds:GetLastError 00415884 cmp eax, 5 00415887 jnz short loc_4158A0 00415889 00415889 loc_415889: ; CODE XREF: _WinMain@16+141j 00415889 push dword_42C020 0041588F call ds:CloseHandle 00415895 push offset aSoftwrapCann_0 ; "Softwrap cannot be run with RegMon load"... 0041589A call sub_409964 0041589F pop ecx 004158A0 004158A0 loc_4158A0: ; CODE XREF: _WinMain@16+14Cj 004158A0 push ebp 004158A1 push ebx 004158A2 push 3 004158A4 push ebp 004158A5 push 3 004158A7 push edi 004158A8 push dword_42C9B8 004158AE call esi ; CreateFileA <- Again the same.... 004158B0 cmp eax, 0FFFFFFFFh 004158B3 mov dword_42C020, eax 004158B8 jnz short loc_4158C5 004158BA call ds:GetLastError 004158C0 cmp eax, 5 004158C3 jnz short loc_4158DC 004158C5 004158C5 loc_4158C5: ; CODE XREF: _WinMain@16+17Dj 004158C5 push dword_42C020 004158CB call ds:CloseHandle 004158D1 push offset aSoftwrapCann_0 ; "Softwrap cannot be run with RegMon load"... 004158D6 call sub_409964 004158DB pop ecx 004158DC 004158DC loc_4158DC: ; CODE XREF: _WinMain@16+188j 004158DC push ebp 004158DD push ebx 004158DE push 3 004158E0 push ebp 004158E1 push 3 004158E3 push edi 004158E4 push dword_42C9BC 004158EA call esi ; CreateFileA <- Filemoncheck too, hehe 004158EC pop edi 004158ED pop esi 004158EE pop ebp 004158EF cmp eax, 0FFFFFFFFh 004158F2 mov dword_42B900, eax 004158F7 pop ebx 004158F8 jnz short loc_415905 004158FA call ds:GetLastError 00415900 cmp eax, 5 00415903 jnz short loc_41591C 00415905 00415905 loc_415905: ; CODE XREF: _WinMain@16+1BDj 00415905 push dword_42B900 0041590B call ds:CloseHandle 00415911 push offset aSoftwrapCann_1 ; "Softwrap cannot be run with FileMon loa"... 00415916 call sub_409964 0041591B pop ecx 0041591C 0041591C loc_41591C: ; CODE XREF: _WinMain@16+1C8j 0041591C push [esp+arg_0] 00415920 call sub_415648 00415925 pop ecx 00415926 call sub_410F8E 0041592B call sub_411138 00415930 xor eax, eax 00415932 retn 10h 00415932 _WinMain@16 endp
End partial code
That was pretty clear I think. Just change those JNZ 's to JMP's and
it's wasted. Or you can just use FrogSice.
The RegMon and FileMon checks didn't succeed on my system: I was able
to run them without any problem. I also noticed that also the registery
is checked for SoftICE and RegMon and Filemon. If those last two are found,
their .vxd's become temporarely disabled. Well, I'll just show you what
RegMon showed me
(RegMon Output):
HKLM\System\CurrentControlSet\Control\SessionManager\KnownVxDs (1.)
HKLM\Software\Softwrap\C8805C2733F945920BE5D4B6B3E1A0851FD4E214 (2.)
HKCR\smallfont\shell\open (3.)
(1.) This checks for RegMon / FileMon VxD's. You can bypass this
by moving the directories where they're installd without putting a link
to them.
(2.) There's the license
(3.) There's another license, pretty stealthy. Has nothing to do
with a "smallfont" or something.
Before trying to crack the time-limit, usage limit, or anything else,
let's take a look to the anti-crack mechanism. To do this, just tamper
with a .sw file, or temper with the license in the registery. When you
run the loader again, you'll get the message that you attempted to crack
it. It will recreate the license.
Bad boys as we are, we tamper again. Run the loader again and SoftWrap
will tell you that you tried a second hacking attempt and that you can't
use the software no more. A message "Two hack attempts have been
detected. Unfortunately this program blablabla....The surgeon general
says hacking is bad for you :)"
Well, I have another surgeon general who says that hacking is very good
for my health, and I rather believe mine then SoftWrap's one :-P
Start partial code
0040AF67 loc_40AF67: ; CODE XREF: sub_40ADC3+14Cj 0040AF67 cmp byte_42BF29, 0 <- First check 0040AF6E jz short loc_40AFB6 <- Jump if no hacking attempts detected 0040AF70 mov eax, [ebp+arg_4] 0040AF73 and dword_42C934, 0 0040AF7A and byte ptr [eax], 0 0040AF7D cmp byte_42BF28, 0 0040AF84 jz short loc_40AF9B 0040AF86 push 1 0040AF88 push edi 0040AF89 push offset aTwoHackAttempt ; "Two hack attempts have been detected. U".
End partial code
Just changing the JZ into a JMP is not enough. You have to put the right
value into the memory location, because it gets checked a lot of times
more. You should change it like this:
mov byte_42BF29, 0
jmp short loc_40AFB6
There still is another check.....so let's go to loc_40AFB6 (the location
our JZ jumps to if we didn't tried to crack the loader)
Start partial code
0040AFB6 loc_40AFB6: ; CODE XREF: sub_40ADC3+1ABj 0040AFB6 movsx eax, byte_42BEE3 0040AFBD sub eax, 42h 0040AFC0 jz loc_40B37E <- jumps if there's no time trial or trial usages 0040AFC6 dec eax 0040AFC7 jz loc_40B16B <- jumps if there's a time trial 0040AFCD dec eax 0040AFCE jz loc_40B074 <- jumps if there's a usage trial 0040AFD4 sub eax, 0Ah 0040AFD7 jz short loc_40B014 <- jumps if there are no limitations (that's what we want) 0040AFD9 sub eax, 7 0040AFDC jnz loc_40B394 <- "if none of the above jumps jumped, they cracked me!" 0040AFE2 push [ebp+arg_4] 0040AFE5 mov eax, dword_42BF18 0040AFEA sub eax, dword_42BF14 0040AFF0 push offset off_423584 0040AFF5 push edi 0040AFF6 push eax 0040AFF7 call sub_40A48C 0040AFFC mov eax, dword_42BF18 0040B001 add esp, 10h 0040B004 mov [ebp+var_4], eax 0040B007 mov eax, dword_42BF14 0040B00C mov [ebp+var_8], eax 0040B00F jmp loc_40B394 <- "if they disabled the "they cracked me jump" i can still jump :P"
End partial code
If you're wondering how I found out about those jumps: just disassemble
the loader .exe and follow the jumps, you'll notice string references.
You can always set a breakpoint on those jumps in SoftICE and make the
jump and look what you'll end up with.
Now, remember when I said that it's not enough to change the jumps, but
that you also have to adapt the memory locations? Same here! This is how
I changed it:
Start partial code
0040AFB6 loc_40AFB6: ; CODE XREF: sub_40ADC3+1ABj 0040AFB6 mov byte_42BEE3, 42h <- Putting the right value into the memlocation 0040AFBD mov eax, 42h 0040AFC2 nop 0040AFC3 nop 0040AFC4 nop 0040AFC5 nop 0040AFC6 dec eax 0040AFC7 jz loc_40B16B 0040AFCD dec eax 0040AFCE jz loc_40B074 0040AFD4 xor eax, eax 0040AFD6 nop 0040AFD7 jz short loc_40B014 <- When we're here eax is zero and our jump will jump
End partial code
When you made all the changes in Hiew (or any other hex editor you prefer),
fire it up, and see that you can use it as long as you like it. And yes
I know, there's still a nag left. I think it's up to you to remove it.
To do you a favor I'll give you the location where the nag is created:
40A25E . No thanks ;-P
Again, making a patcher for this loader only is enough to crack all loaders.
I tested this with a self-wrapped Notepad ;-)
Part2: Unwrapping
****************
This will be a very short part. Well, it costed me some time to find
out, but to explain it's extremely easy. In short, the loader works this
way: perform anti-cracking / trial checks, if okay then decrypt vital
code, create a new process (to run the locked.exe), write the decrypted
code to the process, write garbage to memory to prevent dumping, run the
process, exit the loader.
About most of this is executed in this part of code (just set a breakpoint
on CreateProcessA to get this location). The trick is to dump the whole
stuff before it gets messed-up.
Start partial code
0040C3F2 loc_40C3F2: ; CODE XREF: sub_40C0B5+330j 0040C3F2 lea eax, [ebp+var_84] 0040C3F8 push eax 0040C3F9 lea eax, [ebp+var_74] 0040C3FC push eax 0040C3FD push ebx 0040C3FE push ebx 0040C3FF push 4 0040C401 push ebx 0040C402 push ebx 0040C403 push ebx 0040C404 push edi 0040C405 push ebx 0040C406 call ds:CreateProcessA <- Startup locked.exe file 0040C40C test eax, eax 0040C40E jnz short loc_40C43C
....some code skipped...
0040C455 lea eax, [ebp+var_28] 0040C458 push eax 0040C459 lea eax, [ebp+var_60C] 0040C45F push [ebp+var_20C] 0040C465 push eax 0040C466 push [ebp+var_208] 0040C46C push [ebp+var_84] 0040C472 call ds:WriteProcessMemory <- Write decrypted code to locked.exe in memory 0040C478 test eax, eax 0040C47A jnz short loc_40C48F 0040C47C call ds:GetLastError 0040C482 push eax 0040C483 push offset aCanTWriteToExt ; "Can't write to external process memory "... 0040C488 call sub_409964 0040C48D pop ecx 0040C48E pop ecx 0040C48F 0040C48F loc_40C48F: ; CODE XREF: sub_40C0B5+3C5j 0040C48F push esi 0040C490 push ebx 0040C491 push [ebp+var_C] 0040C494 call _memset 0040C499 push [ebp+var_C] 0040C49C call _free 0040C4A1 inc dword_42BF14 0040C4A7 push offset unk_42BEF4 0040C4AC call sub_40CC9A 0040C4B1 add esp, 14h 0040C4B4 call sub_40FA59 0040C4B9 push dword_42C930 0040C4BF call ds:CloseHandle 0040C4C5 push [ebp+var_80] 0040C4C8 mov dword_42C930, ebx 0040C4CE call ds:ResumeThread <- Execute until here, but DO NOT EXECUTE THIS INSTRUCTION! 0040C4D4 pop edi 0040C4D5 mov byte_42C9E5, 1 0040C4DC pop esi
End partial code
When you are on the call ResumeThread, make
the program freeze so you can leave SoftICE and can dump the FULL process
with Procdump. How to do this?
1. type 'a eip' (enter). This means: assemble
a instruction at location EIP (note that eip contains the offset of execution
i.e. the point you are at the moment of execution)
2. type 'jmp eip' (enter) This will insert
a jump that will jump to itself, making an infinite loop ;-)
3. leave SoftICE and dump the whole process
with Procdump
4. when done, get back into SoftICE and clear
the infinite jump (again with 'a eip' and putting some NOP's until the
call ResumeThread is gone, and you can see the three next instructions.
if you don't do this properly, your machine may hang, or the loader may
exit with an error)
Now run your dumped file and it should work! Protection wasted ;-)
Last thing to do is to remove the SoftWrap icon from the dumped file.
How? With ExeScope (get it at http://protools.cjb.net).
First export the original icon from the launcher .exe with ExeScope, then
open your dumped file with ExeScope and import the icon you just exported.
Save the changes on exit. Job done!
|