Description Now this is truly an excellent piece of software, the best of its kind
really, and it also has one of the most interesting protection schemes
I've come across so far.
Protection Type Serial Number.
Target Name Remote Administrator v1.11 by cLUSTER.

"Well, you don't need my comments for this tutorial, read it for yourselves, this is the sort of intermediate type of protection debunking I'm very pleased to host on my site". "Slightly edited by CrackZ".

Dmitry Znosko has put a lot of effort into making this application virtually uncrackable using traditional cracking approaches,
such as serial-fishing and code-patching, us reversers however always come up with new and innovative ways of approaching our targets and find our ways about to make it obey our will!. Still, this one has actually been on the stand before although none of the former crackers have succeeded to make a 100% working crack.

The first attempt was made by someone in PGC, I don't remember who, however, he failed miserably. He managed to remove the NAG, and it also seemed registered, except for not showing any name and also saying 0 licenses. Now, this we could have lived with, IF he had at least managed to remove the checksums, which caused radmin to crash every time you added a new host or tried to connect to a server. Such a crack is not of much use, disabling the core functionality of the application.

The second attempt made by Staier (tutorial can be found on Fravia) on how to reverse this target by dumping the unpacked module and then disassembling it using IDA might be an interesting way of doing it, but we still don't end up with a fully registered application, instead it is still unregistered with the annoying nag showing and without any name/licenses, only the expiration has been removed. This method of reversing is too time consuming considering what we can achieve using it and also that it is fairly easy to find the piece of code that checks the registration using SoftICE. But obviously that wasn't even what Staier had in mind, instead he concentrated on removing only the expiration checks, maybe because a deadlisting does not have any string references to where the regflag for registration is located :-).

After numerous hours of analysing the code and its bitching, I feel confident to say that I found a truly excellent way of terminating the need for any registration code or even any patched code. Turn On, Tune In and may this tutorial shed some light upon new ways to follow in the art of reverse engineering..

Tools Used: SoftICE, Custom Loader.

NOTE: This application uses relative addresses for its unpacked code, so the code-snippets addresses below might differ from the ones you will get when reversing radmin.

For starters, lets look at what we have here.. Running radmin for the first time tells us that it is an "unregistered copy" and that we can unlock it entering a registration code. Now we feel all confident. There is a way to make it registered using a
registration code. This shouldn't be all that hard, should it? So, we click Enter Code and a dialog box shows up, asking us for the registration code.. Hmm.. No name.. Either this is gonna be quite easy to fish.. Using a hardcoded serial or maybe parts of the reg. code generates the other parts of it.. Or if we're out of luck it is going to be a real bitch of a protection using checksums, maybe even the system id and who knows what else...

Enough speculating, lets find out.. First we enter our registration code..


Yeah, that's it.. This is nice combination of chars since it isn't very likely to be laying around somewhere in memory already.

Now lets break into SoftICE and put a breakpoint on hmemcpy. BPX hmemcpy ; the almighty undocumented feature especially implemented for us reversers.. coming soon to a winnt/2k machine near you! ...not!

And then we click OK. It breaks into SoftICE. Since we don't usually enjoy F12'ing our way out of calls, let's just put a BPRW on the processes name instead. (use MOD to see names). BPRW radmin ; this causes softice to break when the application code starts to execute again. Exit SoftICE and let it rip. Back to the application and no break... Now what's this.. As I see it there are two possible reason why SoftICE didn't break. One is that the application is packed, this is the most likely one. Or it might even be crypted (breakpoint protected).

The other is that there is a second executable running that handles all the checking that we missed out on. Less likely since there are just 2 executables installed and the other executable being the server. (It could not have been a DLL/VXD, since SoftICE catches all such calls).

Well, let's do it all over again.. This time using F12 instead of BPRW.

Success.. This time we end up at :-

B46126 MOV EDI, [USER!EndDialog] (I take for granted that you use exports).

Now this is quite an odd memory location. But still, it is part of radmins code.. (check lower right corner in SoftICE)

Still, since I did bring up the subject on external DLL/VXD's used by the application, let's have a look at which ones radmin uses.

QUERY radmin

While browsing through the Query status of radmin we should look at the Owner (xxxxxxxx) to locate any used DLL/VXD's.
No, nothing out of the ordinary except for a whole lot of memory space allocated for use and the ordinary Windows DLL's.
Out of curiosity we'll have a look at radmins bit sections to see if there is any sections we recognise (of any known packers).

MAP32 radmin

Owner  Name   Obj #    Address      Size   Type
RADMIN .TEXT  0001 0167:01401000 00008D46 CODE RO
RADMIN .RDATA 0002 016F:0140A000 00001952 IDATA RO
RADMIN .DATA  0003 016F:0140C000 0002c418 IDATA RW
RADMIN .RSRC  0004 016F:01439000 00025500 IDATA RO
RADMIN .RELOC 0005 016F:0145F000 00000A30 IDATA RO

These are all common section names from executables. Yet looking at the section addresses tells us where radmins code is
mainly located (the packed code that is), and our current EIP being B46126 confirms that we are indeed tracing a piece of unpacked code. But why do we care? We are going to get ourselves a working reg. code. and if we ever need to investigate what packer has been used, if any known, we'd just use any of the existing exe analysers. I'd recommend File Analyser since it has proven to detect most common packers and also gets updated often. Radmin has it's very own packer though, so
none of the existing exe analyser will detect any packer being used with the executable.

Anyway, let's get with the program.. standard routine here.. we'll just put a breakpoint-on-range on our reg.code string in memory and let radmin run and we will probably end up in some comparison routine and we're all set.. or maybe not.. Off we go.. (NOTE: BPR is not available in WinNT). First of all we need to find out where our reg. code string is located in
memory.. Tracing a couple of lines and we'll end up here :-

B46135 MOV EDX, [ESP+0C]

Do a D EDX to see memory contents.. there is our reg. code.

We'll do a BPR EDX EDX+A R to make SoftICE break when radmin reads from our reg.code string. We exit SoftICE and wait.. Several microseconds later, and we're back in action. This time at...

B44618 MOV AL,[EBX] ;Moves 31 to AL (31=1 from our string 1234554321).
...... XOR ESI,ESI
...... PUSH EDI
...... MOV EBP,EDX
...... TEST AL,AL ;Checks if there is anything in AL.
...... JZ B446FC ;If not, that is if we didn't enter any code, it jumps.
...... MOV CL, [EBX+1] ;Moves 32 to CL (next char in our string).
...... TEST CL,CL ;Checks if there is anything in CL
...... JZ B446FC ;If not, this is not a valid code, and it jumps.

B44634 CALL B8A14

At this call we need to pay some attention. When tracing into this call, some 280kb higher in memory, we see yet another
call to a even higher address (4.5 Mb higher).

B8A14A PUSH 0000001E
...... CALL FE0540

Radmin being 390 kb's in its original packed size, then the former piece of code (b44xxx->b8axxx) makes sense when it comes to size in memory.. But, some 4.5 MBs further up in memory doesn't. Seems as if radmin has been unpacking itself to
several locations in memory.. But let's not bother with this right now though..On with the show...Let's trace into the call.

FE0540 PUSHAD (pushes all registers to the stack)

<start of code>
FE0571 XOR EAX, [EBX*4+008BD934] ; checksums the code
loop back to <start> of code until done with range of addresses.

FE059D ADD EAX, D91A65C5 ;Adds a static value to the checksummed EAX value.
...... MOV EBX, [ESP+20] ;Moves out an address to EBX.
...... SUB EBX, EAX ;Subs the address with what is left in EAX.
...... MOV [ESP+24], EBX ;Moves the results of the sub to the stack.
...... POPAD ;Pops back all registers
...... RET ;Exits

Now what happens in the above code is that it points to an address of radmins unpacked code and then loops, inc's address and does a checksum on the code in each loop until it has completed the loop entirely. Then it uses the checksummed value, which if correct, will result in reaching the correct address to be executed when it has exited this call and the previous one.

So, if we were to successfully unpack this piece of code (or just use an in-memory patcher) and patched some of its code, radmin would crash since the address it would execute after the checksum routine would be way out of radmins code. Now I got you thinking.. "This guy sucks.. Nimas problemas.. I'll just go ahead and patch these checksums.. Been there done that!.."

Not this time, this is a no can do situation. Since what we will see in the coming CALL's we trace is that every piece of checksum code is unique.. It never uses the same static value once and that means we would have to patch each and every one in their very own way.. Sure this is theoretically possible.. But it'd be plain stupid!. Hold it.. Stop right there.. Now I got you thinking again. "This guy is seriously retarded.. It's easy.. Why patch the checksum routine that contains the static value that is screwing us up? I'll just go ahead and find out what address it calls once passing the checksum, and then patch the call that jumps to checksumming code and make it call the correct piece of code directly..This is no match for me..".

Bam Bam!.. General Protection Fault. Since what we will also realise is that EVERY piece of code in this application gets checksummed. That is, if you were to patch a single line of code, it would trigger the checksum that checks this particular range of addresses, and removing this checksum as well would just trigger the next one.. and so on. In other words, this application is a bitch to patch.. So we better hope there is a good way of fishing/generating a valid reg. code.

Back to where we were tracing, that is, after the checksum code.

Code snippet of previous traced code -> current EIP ...

B8A14A PUSH 0000001E
...... CALL FE0540
...... RET <<<<<<<<<<<<<<<<<< WE ARE HERE !!

After this RET, we will end up at the address of the checksum.

B441F3 ADD EAX, -2B ;32 + -2B = 7.
B441F6 CMP EAX, 4F ;Why this? well, 4F+2B = 7A ("z").
B441F9 JA B44380 ;Not valid char, jumps.
B441FF JMP [EAX*4+00B44384] ;7*4+B44384 = [B443A0] = 0C 42 B4 -> B4 42 0C

B4420C MOV EAX, 00000002
B44214 RET

What the above code does is take the second char in our string, contained in CL from the former code, which is 32h = "2", and when the relative jump is made, the same decimal value is moved into EAX but now in hex form.

So, 31 -> 01 , 32 -> 02 ... etc..

After this RET we're back at main stream again.. Where we were before the checksum call, at B44639, from which it continues to checksum the entered reg. code, looping in a huge piece of code until the entire reg. code string is done, ending up at B44701. At this point it is time to ask ourselves what our approach to the situation is going to be.. Are we going to spend hours and hours analysing the code that generates the checksum as well as the coming parts that will compare the checksum result with checksums and checksum and checksums.... get real!. What we want to do is to beat this protection in ANY way and make this application fully registered as well as functional.. Why put hours or maybe days of hard work to eventually succeed in making a keygen for this application.

So far the protection has been pretty impressive, so we can take for granted that reversing the protection scheme into being
able to generate our own valid reg. code(s) would be on the edge of insanity. From here on we will try to locate where radmin compares our faulty generated checksum-code with whatever and see if we can fool it some way. I know, I know.. Patching the code won't be easy, but that is a problem we will have to deal with later.

Back to reversing..After B44701 where it makes a RET it steps back in the code flow to :-

B4614A MOV EAX, [ESP+8] ; [ESP+8] = 81 (part of checksumming)
B4614E TEST EAX,EAX ; Checks if the reg. code checksumming function successfully executed.
B46150 JNZ B46157 ; If so, jump.

B46157 MOV EDX, [ESP+8] ; [ESP+8] = 81 (part of checksumming).
B4615B LEA ECX, [ESP+000003F4] ; [ESP+000003F4] = Our regcode, in its checksummed format.
B46162 SHR EDX, 3 ; 81 -> 10 this is the length of our reg. code in checksummed format.
B46165 CALL B8A2C0 ; This call creates a registry key \SOFTWARE\RAdmin\v1.01\ViewType\Data                      containing the checksummed reg. code.
B4616A CALL B8A2CB ; Gets the registry key reg. code.
B4617D PUSH 00

Until the location above where it calls SetDlgItemTextA, still no comparison with the checksummed reg. code had taken place, and after this call it was all over. The call to EndDialog ended it all. I was a bit confused here but after some more investigation I found out that the call to the final checking was made within the SetDlgItemTextA call itself. Let's do the following to get to the code that gets called from inside the API.

S 0 l c0000000 "02345665432" (take note, the first char is now an "0").

We'll find several memory locations with this string in it. On two of these locations the string will look like this:


Here we put BPR's on those two addresses and then let radmin run again. We will now end up in a loop that generates the checksummed code. (To those of you that have traced all code until this point, yes it is the same code as before that generated the checksummed reg. code). Once in this loop we will F12 us out of this call. Now we end up at B44914, from here forward until B44946 the actual comparisons of the checksummed code takes place.

Now, this is where things starts to get interesting again. Let us have a look at some code snippets :-

B44946 TEST EAX,EAX ; Regflag test. Is it a valid checksummed reg.code?
B44948 JNZ B44A4B ; If not, jump!
B4494E MOV CL, [ESP+18] ; Move a byte from [ESP+18] to CL
B44952 MOV AL, 16 ; Move 16 to AL
B44954 CMP CL, AL ; Compare AL (16) with CL (00)
B44956 JNZ B44A4B ; If not the same, jump!
B4495C CMP [ESP+19], AL ; Compare [ESP+19], AL (16)
B44960 JNZ B44A4B ; If not the same, jump!
B44966 CMP [ESP+1A], AL ; ....
B4496A JNZ B44A4B ; ....
B44970 CMP [ESP+1B], AL ; ....
B44974 JNZ B44A4B ; ....

Let's start with this part of the code. First of all we must pass the regflag test, we'll do a R EAX=0 for the time being.

Next up, it compares the range [ESP+18 - ESP+1B] with 16's. We'll simply E [ESP+18] at B4494E and enter four 16's there.

Tracing the next few lines leaves us clueless of what it wants, so let us just exit SoftICE and let radmin run and see what
happens. Great!.. It says Registered.. But, to no-one and with 0 licenses. Now this is not as great.. But we're on a roll here, let's get on with the reversing.. We might just get lucky? :-). Let's have a look at what follows :-

B4497A MOV EAX, [ESP+1E] ; Moves a word from [ESP+1E] to EAX
B4497E MOV ECX, [ESP+1D] ; Moves a word from [ESP+1D] to ECX
B44982 MOV EDX, [ESP+1C] ; Moves a word from [ESP+1C] to EDX
B44986 AND EAX, 000000FF
B4498B SHL EAX, 08
B4498E AND ECX, 000000FF
B44994 AND EDX, 000000FF
B4499C MOV ECX, [ESP+1F] ; Moves a word from [ESP+1F] to ECX
B449A0 SHL EAX, 08

To quickly get a grip on what is happening here we will do some trial & error.. We edit [ESP+1C - ESP+1F] and put four 11's there. Now exit SoftICE and let radmin run. OK, now we are kicking some serious asses.. Registered, and with 17 licenses. After a few minutes of playing around with this particular memory location, putting all kinds of different values there, we have successfully managed to recreate a working license-string.

from [ESP+18 - ESP+1B] we should put 16's, this must be some kind of checksum.
from [ESP+1C - ESP+1E] does nothing
from [ESP+1F - ESP+20] decides how many licenses there should be (see table below).
from [ESP+21 -> ESP+21+xx UNTIL 00h] string to put after registered to:
from [ESP+xx (AFTER 00h) -> ESP+xx) string to put within the parenthesis.

Maximum length of the entire string is 3e8h = 1000.

Licenses table:

x x x x
1 - 16 licenses
1 - 1 licenses
1 - 4096 licenses
1 - 256 licenses
1 1 - 17 licenses
2 - 32 licenses
2 2 - 8224 licenses
F F F F - 65535 licenses

So putting this string starting at [ESP+18] would make radmin registered with the maximum amount of licenses:

16 16 16 16 00 00 00 FF FF 43 4C 55 53 54 45 52 00 41 53 53 4B 49 43 4B 45 52

That's it.. Protection Terminated!..That is if you feel like using SoftICE every time you want to use radmin and we wouldn't want that now would we?. What must be created is a sophisticated loader.. An in-memory patcher. And NO, you can NOT use any of the existing ones available on the net, since they all lack features that makes it possible to patch apps such as this one. I'm sorry to say that even though most of them have been undergoing development for a long time and they still are very limited.

I will now explain how the loader I use to crack radmin with works, but I will not be giving away any sources with this tutorial. The reason for this is simple, I made this tutorial to show serious reversers how to approach a target such as radmin, not to ruin the developers of radmin by sharing all that is needed for people not being able to reverse a target such as this one themselves.
If you are serious about using radmin you SHOULD buy it!.. The developer of radmin deserves every penny he can get.. He has made a kickass application, and he isn't asking for much, $25 is well worth spent money if you are seriously going to use this application (CrackZ - I strongly echo these sentiments).

Loader approach

Our goal is to reach the address of the regflag test and once we've reached this point, we need stop radmin from running and move the required bytes into memory and then resume the execution of radmins code. To succeed in doing so, we need to implement the following features into our loader:

- We must be able to put breakpoints in code and handle them.
- Read/Write Registers.

If you manage to make a loader with the above features, you will need to take the following under consideration to make a fully working loader...

- The first breakpoint must be set relative to the start of the first unpacked code. Whenever you need to set new breakpoints, and you will have to do so since radmins code gets unwrapped progressively, you should keep in mind that you must put the breakpoints relative the start of the codeblock they belong to, which may be unpacked to different addresses each time the program is run.

Hints: The only static code that jumps to unpacked code is at 1401690. From here you should proceed with the next steps.
Use BPR on the unpacked code to find out from where it gets unwrapped.

If you by some reason manage to get radmin to expired and want to remove the expiration, edit HKLM -> Software and REMOVE the key named DATA.

When putting breakpoints at code that is not yet existing in memory but is about to be unpacked and executed soon, you can
not use BPX with the address, you MUST use BPM address X. Also do not forget to use ADDR to change to the right process before putting any such breakpoints.

I hope that this tutorial was of use.. I've tried to make it as detailed as possible, so that not only the very best reversers could get a grip on what is going on, but also the upcoming masters of the beautiful art of reverse engineering.

Last but not least, I pay my deepest respects to MANMACHINE for not only being a great friend but also for making advanced loaders/patchers and other useful tools become a reality for me to use. I could never have made this one
without you!.

Radmin Reversed & Tutorialized (c) Dec 1999 - [ cLUSTER! ]

Return to Miscellaneous

© 1999, 2000 Hosted by CrackZ, authored by cLUSTER. 12th December 1999.