Download Files available.
This is the first of my dongle tutorials, and in order that I don't damage the authors I have decided not to make the program available for public download. If you are really interested in examining this code then send me an e-mail and I'll make only the necessary files available for you.
Starting GeoPath produces unsurprisingly an error and after what looks like a second attempt to locate the dongle the program exits. Its easy to find the message box with a bpx MessageBox (0002:8A26), this prompts us to immediately examine the disassembly. The programmers however evidently had other ideas, tracing up the message box code 1 level leads us to conclude that CALL 89D6 is bad, but tracing this higher leads to 9 callers and many multiple call references even higher still. It just isn't practical to try and patch all of these occurences or trace every single caller back.
SoftICE time, a bpio -h 378 rw is the usual line of attack for any LPT dongle, and sure enough launching GeoPath produces a break. It turns out this code is actually inside something called sentinel, you can't actually tell which file it is (although its usually a vxd). At this point you can disable the break point and start pushing F12 to find where the real caller is. The program seemed to stay inside sentinel for at least 10 F12's but eventually I got back to sc16w.dll which is the dongle manufacturer's dll.
I traced through some of the dongle dll code (although not for very long), my advice is simply, unless your prepared for a serious cracking session don't screw with the dongle code, keep pushing F12 until you get to the application side, which must do something. Eventually after a trip through vmm I got back to scadcam.exe. Your attention is now drawn to the first break inside scadcam.exe.
:0002.0744 MOV DX,AX <-- BPIO entry point.
:0002.0746 CMP DX,FFFD <-- DX is 0 here.
:0002.0749 JG 0758 <-- Jump and initiate dongle communication.
:0002.0758 CMP DX,FFFF <-- Now compare DX with -1.
:0002.075B JZ 07D4 <-- Possibly some unrelated error.
:0002.075D PUSH 003F <-- This almost certainly makes space on the stack for dongle data.
:0002.075F CALL FAR WORD PTR [BP-0A] <-- Read dongle.
:0002.0762 MOV DX,AX <-- Return code probably placed in AX moved to DX.
:0002.0764 CMP DX,268F <-- This looks as if it must be a good dongle return.
:0002.0768 JNE 07D4 <-- This 'feels' bad.
I'll stop here and just explain my reasoning, the JG check looks like an unrelated
error of some description, why?, well to fail this check you'd need AX returned
less than -3 and then this is checked against -1?, regardless of AX's value
the code is going to reach 0758 anyhow. The FAR call is a give away trait of
dongle communications and for compiler/SoftICE reasons you can almost guarantee the
result in (E)AX, needless to say when you trace over this call AX is FFFF (-1), 268F
is just too abstract to be anything else other than the good result so a
patch here seems in order.
Continuing.
:0002.076A PUSH 0000
:0002.076C CALL FAR WORD PTR [BP-0A] <-- Read dongle again.
:0002.076F MOV DX,AX <-- Once again, move return code into DX.
:0002.0771 CMP DX,1F1F <-- Compare with 1F1F.
:0002.0775 JNZ 07A8 <-- Jump here.
This next code is really sneaky, you could well be forgiven for believing that 1F1F was a good return code, in fact its not, its a fake and very well concealed. I'll explain, if you examine the code after this it *looks* as if the program calls into the dongle to make another 2 checks storing the results in memory locations [9EFC] and [9EFE], not having the dongle presents a problem because we have no idea what those values are supposed to be, but a few lines on [9EFC] is tested for FF and the key thing is that regardless of the result the code proceeds to 07D4.
At 07D4 the code then checks flags at locations BP+06 and BP-14, but our path here doesn't set either of these flags, this results in a loop counter [0084] being started and incremented 6 times back where we started. This can lead only to the conclusion that 1F1F is a trick. In fact not having the dongle is a positive advantage for the 1F1F check because we fail it anyway.
:0002.07A8 CMP DX,1010 <-- Another return code.
:0002.07AC JNZ 07B0 <-- Jump here and check return code again.
:0002.07AE JMP 07B6 <-- Jumps to same location as the next check.
:0002.07B0 CMP DX,F010 <-- Another return code check.
:0002.07B4 JNZ 07C3 <-- Jump to yet another check.
This next code is also very interesting, however it seems that if DX is either 1010 or F010 the code reaches 07B6 regardless, and this results in some flags being set. If neither code is correct we reach a final check at 07C3.
:0002.07B6 MOV WORD PTR [BP-14], 0001 <-- Flag.
:0002.07BB MOV WORD PTR [9EFA], 0001 <-- Another location.
:0002.07C3 CMP DX,1210 <-- Final return code check.
:0002.07C7 JNZ 07D4 <-- Jump obviously bad.
:0002.07C9 MOV WORD PTR [BP-14], 0001 <-- Same flag as earlier.
:0002.07CE MOV WORD PTR [9EFA], 0002 <-- Location flagged as 2.
The [BP-14] flag is always flagged 1 and is therefore unimportant, the question is which value of [9EFA] is good, (1 or 2). Without the dongle its nigh on possible to really be sure, although by fishing the disassembly I reckoned that 1 was more likely to be the good flag, as it turns out this is indeed the case, the 2 flag actually acts as a function disable switch for certain operations although you would only know this with prior knowledge. There does also seem to be 1 other location where the dongle is called, you can easily locate it by searching for the hex for the CALL FAR dongle read instruction. Patching it is evidently easy.
I actually consider this to be quite a good dongle protection, although I feel more checks could have been made and several more traps added. Without having a tester the [9EFA] flag is a real problem, although its evidently not a really great hassle to try one or the other. Patching this code is of course a fairly routine task although the usual aesthetics should apply.