Results 1 to 5 of 5

Thread: An unusual driver based Time-trial protection

  1. #1
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,127
    Blog Entries
    5

    An unusual driver based Time-trial protection

    Hi All,

    I thought I'd mention a little driver based time-limited demo found running loose in the wilds...

    I was examining a 'security' driver recently, with a friend and fellow member, to see how it operates. Purely academic reversing you understand, so I was quite naturally concerned that its 15-day time trial might interfere with our long term research plans... ;-)

    Briefly, it hardcodes the download date (y/m/d) within the .data section of the sys driver, which is bundled with 5 other executables (exe/dll) into a single install file. If you download the install file the next day from the server, the file has been updated to the new date, the only changes between the 2 files. We'll call this weakness #1...

    The driver, which loads on system startup, uses KeQuerySystemTime to get the current date, then uses RtlTimeFieldsToTime to convert its hardcoded download date from the .data section, to a comparable format. Then there is a simple comparison and an ExpiredFlag is set.

    The ExpiredFlag is checked in 3 different ways. There is a DeviceIoControl call by the main GUI app when it starts up, which simply checks if the ExpiredFlag is set in the driver and returns. If expired, a Nag dialog pops up, thence to _Exit. The other 2 ways are slightly more interesting.


    The driver itself is designed to monitor applications starting up as part of its functionality, along with hooking certain IDT and ServiceDescriptorTable vectors, and making version-specific patches to ntoskrnl. It uses both PsSetCreateProcessNotifyRoutine and PsSetCreateThreadNotifyRoutine to register system callback routines, which are user-defined functions which will be notified any time a new process or thread is created or destroyed.


    The PsSetCreateProcessNotifyRoutine callback has only 1 purpose - every time an application on your system starts/ends, there is a further check using KeQuerySystemTime and RtlTimeFieldsToTime to set (or not) the ExpiredFlag.
    Code:
    ProcessNotifyRoutine: 
    call    querytime   ; KeQuerySystemTime + RtlTimeFieldsToTime
    test    eax, eax
    jnz     @F
    mov     ExpiredFlag, 1
    @@:
    retn    0Ch
    The 2nd callback registered to the system, by PsSetCreateThreadNotifyRoutine, monitors thread creation and deletion, and is the actual workhorse of the driver. But what it *also* does is sneakily take a look at the ExpiredFlag once again and act accordingly.
    Code:
    (*PCREATE_THREAD_NOTIFY_ROUTINE) (
        IN HANDLE  ProcessId,
        IN HANDLE  ThreadId,
        IN BOOLEAN  Create
        );
        
    ThreadNotifyRoutine:
    ...
    mov     edx, [ebp+ProcessId]
    lea     ecx, [ebp+var_4]
    push    ecx    ; OUT PEPROCESS   *Process,
    push    edx    ; IN PVOID        ProcessId
    call    PsLookupProcessByProcessId
    test    eax, eax
    jl      _exitThreadNotifyRoutine
    mov     eax, ExpiredFlag
    test    eax, eax
    jnz     _exitThreadNotifyRoutine
    ...
    And finally, the hardcoded date check itself:
    Code:
    ; Format of embedded trial date in the .sys driver data section
    ;    .data:0 HardcodedTrialDate_year dd 7D518h
    ;    .data:4 HardcodedTrialDate_month dd 200h
    ;    .data:8 HardcodedTrialDate_day dd 1A00h
    
    QueryTime       proc near
    
         CurrentTime     = LARGE_INTEGER ptr -20h
         Time            = LARGE_INTEGER ptr -18h
         TimeFields      = TIME_FIELDS ptr -10h
         
    .text:10                 sub     esp, 20h
    .text:13                 push    ebx
    .text:14                 push    esi
    .text:15                 lea     eax, [esp+28h+CurrentTime]
    .text:19                 push    edi
    .text:1A                 push    eax             ; CurrentTime
    .text:1B                 call    ds:KeQuerySystemTime ;
    .text:1B                               ; KeQuerySystemTime obtains the current system time
    .text:1B                               ;
    .text:1B                               ; KeQuerySystemTime(
    .text:1B                               ;     OUT PLARGE_INTEGER  CurrentTime
    .text:1B                               ; );
    .text:1B                               ;
    .text:21                 mov     esi, HardcodedTrialDate_month
    .text:27                 mov     edi, HardcodedTrialDate_day
    .text:2D                 mov     ebx, HardcodedTrialDate_year
    .text:33                 xor     ecx, ecx
    .text:35                 mov     dword ptr [esp+2Ch+TimeFields.Year], ecx
    .text:39                 and     esi, 0FFFFh
    .text:3F                 and     edi, 0FFFFh
    .text:45                 mov     dword ptr [esp+2Ch+TimeFields.Day], ecx
    .text:49                 lea     edx, [esp+2Ch+Time]
    .text:4D                 lea     eax, [esp+2Ch+TimeFields]
    .text:51                 shr     ebx, 8
    .text:54                 shr     esi, 8
    .text:57                 shr     edi, 8
    .text:5A                 mov     dword ptr [esp+2Ch+TimeFields.Minute], ecx
    .text:5E                 push    edx             ; Time
    .text:5F                 push    eax             ; TimeFields
    .text:60                 mov     dword ptr [esp+34h+TimeFields.Milliseconds], ecx
    .text:64                 mov     [esp+34h+TimeFields.Day], di ; 1Bh = Day 27
    .text:69                 mov     [esp+34h+TimeFields.Year], bx ; 7D5h = Year 2005
    .text:6E                 mov     [esp+34h+TimeFields.Month], si ; 02h = Month Feb.
    .text:73                 call    ds:RtlTimeFieldsToTime ;
    .text:73                               ; RtlTimeFieldsToTime converts TIME_FIELDS information
    .text:73                               ;  to a system time value
    .text:73                               ;
    .text:73                               ; RtlTimeFieldsToTime(
    .text:73                               ;     IN PTIME_FIELDS  TimeFields,
    .text:73                               ;     IN PLARGE_INTEGER  Time
    .text:73                               ; );
    .text:73                               ;
    .text:73                                    ; TimeFields
    .text:73                                    ; Points to the following structure, containing
    .text:73                                    ;  the time information to be converted:
    .text:73                                    ; typedef struct TIME_FIELDS {
    .text:73                                         ;     CSHORT Year;
    .text:73                                         ;     CSHORT Month;
    .text:73                                         ;     CSHORT Day;
    .text:73                                         ;     CSHORT Hour;
    .text:73                                         ;     CSHORT Minute;
    .text:73                                         ;     CSHORT Second;
    .text:73                                         ;     CSHORT Milliseconds;
    .text:73                                         ;     CSHORT Weekday;
    .text:73                                         ; } TIME_FIELDS;
    .text:73                                         ;
    .text:79                 mov     ecx, [esp+2Ch+CurrentTime.HighPart]
    .text:7D                 mov     eax, [esp+2Ch+Time.HighPart]
    .text:81                 cmp     ecx, eax
    .text:83                 jl      short _notexpired
    .text:85                 jg      short check_nondemo_magic_value
    .text:87                 mov     edx, [esp+2Ch+CurrentTime.LowPart]
    .text:8B                 mov     eax, [esp+2Ch+Time.LowPart]
    .text:8F                 cmp     edx, eax
    .text:91                 jbe     short _notexpired
    .text:93
    .text:93 check_nondemo_magic_value: 
    .text:93                 cmp     ebx, 709536h     ; and the answer is...?
    .text:99                 jz      short _notexpired
    .text:9B                 cmp     esi, 709536h
    .text:A1                 jz      short _notexpired
    .text:A3                 cmp     edi, 709536h
    .text:A9                 jz      short _notexpired
    .text:AB                 pop     edi
    .text:AC                 pop     esi
    .text:AD                 xor     eax, eax
    .text:AF                 pop     ebx
    .text:B0                 add     esp, 20h
    .text:B3                 retn
    .text:B4 ; ---------------------------------------------------------------------------
    .text:B4 _notexpired:
    .text:B4                 pop     edi
    .text:B5                 pop     esi
    .text:B6                 mov     eax, 1
    .text:BB                 pop     ebx
    .text:BC                 add     esp, 20h
    .text:BF                 retn
    .text:BF QueryTime       endp

    So what we have are 2 driver callback routines that are continually monitoring the Time-trial status while the driver operates, every time a new process or thread is created/deleted. An interesting approach, while regretfully naive, for a "payment non-assurance plan"

    Cheers,
    Kayaker

  2. #2
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    Quote Originally Posted by Kayaker
    and making version-specific patches to ntoskrnl
    ughh... that's not good software design

  3. #3
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,127
    Blog Entries
    5
    Let's see, there are about 26 variables to hold version-specific info, such as index values for the SSDT, EPROCESS/KTHREAD field offsets, etc., plus 2 version specific ntoskrnl patch search patterns, all defined for the 4 common OS versions from NT to Server2003, which makes about er, (26+2)*4, carry the 1, a heck of a lot of,... what you said. It goes with the hack nature of the driver, pretty it's not

  4. #4
    Registered User
    Join Date
    Feb 2002
    Location
    FRANCE
    Posts
    20

    Thumbs up

    Very interesting post Kayaker, these crappy drivers seems to be used on more application than the well known t*k*.sys found on specific music sofwares....Using ssdt and idt and trampolining int1 or int3 always results in a terrific mess whith non permissives homemade rootkits. It is really nosense to sell such things (in fact look like stolen from a russian virii, I disassembled one year ago) as a protection.

    L!sA

  5. #5
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,127
    Blog Entries
    5
    Hi L!sA, I agree with you. Some of these "protections" get too intrusive for their own good. From what I've read, Pace is an excellent example, it's set the professional audio community into an uproar and any software using it, is recommended to be avoided like the plague. It's unfortunate for the developers that they relied on such an aggressive and expensive protection.

    From a discussion group soundly complaining about the driver I found this excellent and chilling essay which should be a lesson to all responsible software developers

    http://www.prorec.com/prorec/articles.nsf/files/4F0B51C39C17DA6386256B7F0077FBA6

    a few comments:

    -----
    "Isn’t it a pity that such intrusive code was introduced to such a benign application as an audio plugin?

    "My experience is clear: products protected by PACE Interlok are incompatible with one another such that uninstalling one can deactivate the others. It’s a shame when an application will not play fair and interoperate with other applications. It’s ridiculous when it will not interoperate with itself.

    The situation is so farcical that the common practice is, “buy the software, but install the crack.” A large majority of people I know and respect have all done exactly that. They purchased the software, so that they own a license, but they installed the pirated version, and so avoided the copy protection altogether.

    You might ask why someone would install the pirated version if they own the license. The answer is that the common wisdom is that the pirated version (which does not contain any traces of PACE Interlok) is more stable, and if you need to reinstall it, you don’t have to request a reauthorization"
    -----

    An interesting reflection on the futility of protections...

    Kayaker

Similar Threads

  1. writing a new driver for a certain protection
    By OHPen in forum Advanced Reversing and Programming
    Replies: 1
    Last Post: January 9th, 2006, 08:55
  2. trial protection
    By _d_ in forum Off Topic
    Replies: 3
    Last Post: June 22nd, 2005, 07:26
  3. Cracking a trial - Time Up dialog text is not in stringdata
    By nog_lorp in forum The Newbie Forum
    Replies: 12
    Last Post: April 9th, 2005, 16:13
  4. Time trial & encryption woes
    By johnnyfiasko in forum Malware Analysis and Unpacking Forum
    Replies: 2
    Last Post: July 3rd, 2002, 09:23

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •