Borland's C++ builder v4
Emulating inputs on a timebomb protection


Jan 17 2000

by Tsehp

Courtesy of Fravia's page of reverse engineering
slightly edited
by tsehp+
There is a crack, a crack in everything That's how the light gets in
Rating
( )Beginner (x)Intermediate ( )Advanced ( )Expert

After I received Macillaci's essay about delphi, I decided to do an attempt on the c++ version, trying to do it a different way on the installshield part.

Borland's C++ builder v4 
Emulating inputs on a timebomb protection

Written by Tsehp
Inspired by Macillaci

Introduction
After I received macillaci's essay, I wanted to try the luck on borland c++, well no surprise, the protection
is all the same. I actually work on windows 2000 and wisdec doesn't work on this system, so we have to use
our brains to find another path.
More and more tools like wisdec and procdump are discontinuited at this time. Hope we still see such great
and useful tools in the future.
Tools required
My system : windows 2000 server, this should work on any windows system.

Any Hexeditor
Softice 4.01
IDA 4.01
IsDCC (installshield decompiler, still working on win2k)

Target's URL/FTP
http://www.borland.com

Essay
1) Installshield crack

First you've got to install this and provide a password that borland can give you if
you provide your email. We are not here to talk about anonymisers so lets crack this 
script, located as always inside setup.ins.
We learned on this site to crack those scripts with hexeditors (see installshield 
cracking section), I can't use wisdec on my system it's not working and this tool is
stopped since 98, so forget it.
Setup.ins contains tokens, interpreted as instructions by the running proc _ins5116.exe,
with tests, jumps all of this is explained in the essays related to that.
On the decompiled script, you find this :

label941:

lNumber1 = 0;

lString0 = "Taj";

lString2 = SUPPORTDIR ^ "cleanup.dll";

UseDLL(lString2);

lNumber2 = LAST_RESULT;

CLEANUP.StartLogFile(lString1);

lNumber3 = LAST_RESULT;

UnUseDLL("cleanup.dll");

StrLoadString("", "TRIAL_TEXT", lString3); *Loads the trial passwd entry nag.

AskText(lString3, "", lString0); * password entered in string0

lNumber4 = LAST_RESULT;

StrCompare(lString1, lString0); *password check

lNumber5 = LAST_RESULT != 0; *this test fails last_result is different than 0.

if (lNumber5 = 0) then *If test ok, this jumps to GOOD BOY, lets patch this one (1)

goto label945;

endif;

lNumber5 = lNumber1 >= 3; *more than three attempts ? 

if (lNumber5 = 0) then

goto label944; *jump to bad guy exit

endif;

abort;

label943: *bad guy messageboxa if the test fails

MessageBeep(0);

StrLoadString("", "WRONG_PSWD", lString3);

MessageBox(lString3, -65535);

lNumber1 = lNumber1 + 1;

StrLoadString("", "TRIAL_TEXT", lString3);

AskText(lString3, "", lString0);

lNumber4 = LAST_RESULT;

goto label943;

(1) Ok we've got to invert the test, it would be easy with wisdec but we will not use
it. Search for TRIAL_TEXT with your hexeditor inside setup.ins, you find this :
 

setup.ins



00012040 0054 5249 414C 5F54 4558 5452 98FF 1E00 .TRIAL_TEXTR....
00012050 6298 FF61 0000 529B FF21 0032 97FF 4200 b..a..R..!.2..B.
00012060 0000 0007 0029 0123 0062 9AFF 629B FF28 .....).#.b..b..(
00012070 0132 96FF 4200 0041 0600 0000 4100 0000 .2..B..A....A...
00012080 0022 0070 B103 9542 96FF 4100 0000 0028 .".p...B..A....(
00012090 0132 96FF 429A FF41 0400 0000 4103 0000 .2..B..A....A...
000120A0 0022 0070 B003 9542 96FF 4100 0000 0059 .".p...B..A....Y
000120B0 0100 0008 003A 0041 0000 0000 1201 6100 .....:.A......a.
000120C0 0061 0A00 5752 4F4E 475F 5053 5744 5298 .a..WRONG_PSWDR.

Well, you see the ascii occurences, if you learned well from the installshield essays,
you know that the conditionnal jump is like this 03 95 label0 ff label1
where 95 is jump if result = 0 (96 if different than 0)
Labels are two bytes like 42 96, they're at the beginning of primary instructions
inside setup.ins.
We invert the jump at offset 12087, 03 95 42 96 -> 03 96 42 96
There are crc checks inside setup.ins, all the bytes are added to form it, we have
to reduce a byte to make the crc work. We better do that inside a ascii text, found
one at offset 58c6 :

000058C0 6119 0055 6E61 626C 6520 746F 2063 7265 a..Unable to cre
lets reduce the b from "unable" to a
-> 000058C0 6119 0055 6E61 616C 6520 746F 2063 7265 a..Unaale to cre

So the crc check will be ok.
Launch it, enter nothing at the password nag and the trial installs itself !
2) Time trial protection (copied from macilaci's essay, those parts are the same, except for the adresses)
Note from tsehp : with ida, you don't need to dump the progs, even when it's crypted and pe are bad, this tool
is able to disassemble thoses place. Buy it !
/***

After I saw what's going on I decided to emulate inputs. The delete approach is effective but not elegant. Stop, I found timefix.exe. Sweet - references to HKLM\SOFTWARE\Ntpad\HELPMENU\tin and some more... Try now run the trial with Boundschecker. Sysprst,.... GetLocalTime!! 0x00d217d =0x004d217d

Let's see:

_0000010:004D6900                 sub     esp, 0CCh
_0000010:004D6906                 lea     eax, [esp+0CCh+var_BC]
_0000010:004D690A                 push    esi
_0000010:004D690B                 push    eax
_0000010:004D690C                 call    ds:GetLocalTime
_0000010:004D6912                 lea     ecx, [esp+0D0h+var_CC]
_0000010:004D6916                 push    ecx
_0000010:004D6917                 call    ds:GetSystemTime
_0000010:004D691D                 mov     cx, ds:word_0_496D02
_0000010:004D6924                 cmp     [esp+0D0h+var_C2], cx
_0000010:004D6929                 jnz     short loc_0_4D6967
_0000010:004D692B                 mov     ax, ds:word_0_496D00
_0000010:004D6931                 cmp     [esp+0D0h+var_C4], ax
_0000010:004D6936                 jnz     short loc_0_4D6967
_0000010:004D6938                 mov     ax, ds:word_0_496CFE
_0000010:004D693E                 cmp     [esp+0D0h+var_C6], ax
_0000010:004D6943                 jnz     short loc_0_4D6967
_0000010:004D6945                 mov     ax, ds:word_0_496CFA
_0000010:004D694B                 cmp     [esp+0D0h+var_CA], ax
_0000010:004D6950                 jnz     short loc_0_4D6967
_0000010:004D6952                 mov     ax, ds:word_0_496CF8
_0000010:004D6958                 cmp     [esp+0D0h+var_CC], ax
_0000010:004D695D                 jnz     short loc_0_4D6967
_0000010:004D695F                 mov     edx, ds:dword_0_496CF0
_0000010:004D6965                 jmp     short loc_0_4D69AD
.../...
_0000010:004D69AD                 mov     eax, [esp+0D0h+var_B0]
_0000010:004D69B1                 push    edx
_0000010:004D69B2                 and     eax, 0FFFFh
_0000010:004D69B7                 push    eax
_0000010:004D69B8                 xor     eax, eax
_0000010:004D69BA                 mov     ax, [esp+0D8h+var_B2]
_0000010:004D69BF                 push    eax
_0000010:004D69C0                 mov     eax, [esp+28h]
_0000010:004D69C4                 and     eax, 0FFFFh
_0000010:004D69C9                 push    eax
_0000010:004D69CA                 xor     eax, eax
_0000010:004D69CC                 mov     ax, [esp+0E0h+var_B6]
_0000010:004D69D1                 push    eax
_0000010:004D69D2                 xor     eax, eax
_0000010:004D69D4                 mov     ax, word ptr [esp+0E4h+var_BC+2]
_0000010:004D69D9                 push    eax
_0000010:004D69DA                 mov     eax, [esp+0E8h+var_BC]
_0000010:004D69DE                 and     eax, 0FFFFh
_0000010:004D69E3                 push    eax
_0000010:004D69E4                 call    sub_0_4DBCE0 ; this returns some strange value in eax and edx
_0000010:004D69E9                 mov     ecx, [esp+0ECh+arg_0]
_0000010:004D69F0                 add     esp, 1Ch
_0000010:004D69F3                 test    ecx, ecx
_0000010:004D69F5                 jz      short loc_0_4D69F9
_0000010:004D69F7                 mov     [ecx], eax
_0000010:004D69F9 
_0000010:004D69F9 loc_0_4D69F9:                           ; CODE XREF: sub_0_4D6900+F5j
_0000010:004D69F9                 pop     esi
_0000010:004D69FA                 add     esp, 0CCh
_0000010:004D6A00                 retn    

Another encryption? Probably yes. Let's see the above routine sub_0_4D69f9:
_0000010:004DBD63                 dec     ebx
_0000010:004DBD64                 lea     esi, [edx+edx*2]
_0000010:004DBD67                 mov     [esp+34h+var_14], ebx
_0000010:004DBD6B                 mov     [esp+34h+var_1C], ecx
_0000010:004DBD6F                 lea     edx, [esi+esi*4]
_0000010:004DBD72                 add     edx, [esp+34h+arg_14] ;the final edx value
_0000010:004DBD76                 lea     esi, [edx+eax+7C558180h] ;the final eax=esi value
_0000010:004DBD7D                 mov     eax, [esp+34h+arg_18]
_0000010:004DBD81                 cmp     eax, 1
_0000010:004DBD84                 jz      short loc_0_4DBDA5
_0000010:004DBD86                 cmp     eax, 0FFFFFFFFh
_0000010:004DBD89                 jnz     short loc_0_4DBDAB
_0000010:004DBD8B                 cmp     ds:dword_0_4905E4, 0
_0000010:004DBD92                 jz      short loc_0_4DBDAB
_0000010:004DBD94                 lea     eax, [esp+34h+var_24]
_0000010:004DBD98                 push    eax
_0000010:004DBD99                 call    sub_0_4DE680
_0000010:004DBD9E                 add     esp, 4
_0000010:004DBDA1                 test    eax, eax
_0000010:004DBDA3                 jz      short loc_0_4DBDAB
Write down the edx and eax and replace the location 004D747F:
_0000010:004DBD76                 mov     esi, 38820632h
_0000010:004DBD7B                 mov     edx, 0BC2C84B2h
_0000010:004DBD80                 nop     

Note from tsehp : Be sure that further installs at this point will be the same day, otherwise the later
date tamper subroutine will detect that and make the prog expire.
With a search and replace util, look for the occurences of 4dbd76 : 8D B4 02 80 81 55 7C 8B 44 24 50
You will find the protection in all those files that you must patch:
 
16/01/2000 18:28:58
Search String: \0x8d\0xb4\0x02\0x80\0x81\0x55\0x7c\0x8b\0x44\0x24\0x50
Replace String:
Path: C:\Program Files\Borland\CBuilder4
File Mask: *.*
Search Subdirectories, Search ZIP Files

Processing file : C:\Program Files\Borland\CBuilder4\Bin\bcb.exe
Offset 0xcc776 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\bcbcxp40.bpl
Offset 0x108976 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\bcbidl40.bpl
Offset 0xb9176 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\dbexplor.exe
Offset 0x55776 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\dcldss40.bpl
Offset 0x64576 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\dclmid40.bpl
Offset 0x61576 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\dclnet40.bpl
Offset 0x66d76 - ´ U| D$P
Found 1 occurrences.

Processing file : C:\Program Files\Borland\CBuilder4\Bin\ilink32.exe
Offset 0x93776 - ´ U| D$P
Found 1 occurrences.

Searched 2017 file(s), found 8 occurrences in 8 file(s)

Good idea to locate it in all those places, but it would have been better to change it a little no ? ;-)

3)run without activator

Back to our bounschecker record. Now look at this when the activator is running.
Api reference: WaitForSingleObject and before CreateProcessA in caitf32.dll module:

00401307                 push    0
00401309                 call    j_CreateProcessA        ;here start activator
0040130E                 test    eax, eax
00401310                 jz      loc_0_4013C0
00401316                 test    ebx, ebx
00401318                 jz      loc_0_4013A9
0040131E                 push    0FFFFFFFFh
00401320                 mov     ecx, [ebp-14h]
00401323                 push    ecx
00401324                 call    j_WaitForInputIdle
00401329                 mov     [ebp-4], eax
0040132C                 cmp     dword ptr [ebp-4], 0
00401330                 jnz     short loc_0_4013A0  
00401332                 push    64h
00401334                 mov     eax, [ebp-14h]
00401337                 push    eax
00401338                 call    j_WaitForSingleObject
...
0040138B                 push    edx
0040138C                 mov     ecx, [ebp-14h]
0040138F                 push    ecx
00401390                 call    j_GetExitCodeProcess ;and get the result
00401395                 jmp     short loc_0_4013AE

This subroutine is called from this sub:

004018CC                 push    1
004018CE                 mov     edx, [ebp+arg_0]
004018D1                 push    edx
004018D2                 call    sub_0_401288          ; call the activator routine
004018D7                 add     esp, 14h
004018DA                 mov     ebx, eax

Each time we press TRY button in the eax is returned the 0x00002716 value. Other registers
doesn't affect the program run. Simple replace: 

004018D2                 mov eax, 0x00002716        ;now we can run it without activator

And the patch is done. Our trial is running any time we want.

No time stamp protection on this one.

Ob Duh
I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell, don't come back.

You are deep inside Fravia's page of reverse engineering, choose your way out:


redhomepage redlinks redsearch_forms red+ORC redhow to protect redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_Fravia
redIs reverse engineering legal?