Interlok VxD vagaries
defeating the anti-debug trick inside tpkd.vxd
Written by macilaci

Introduction

VxD protections seem harder to defeat, especially when you need to restart each time. Do the Interlok guys make jokes of you? Be a good guy! Don't load the Winice!. Joking apart, the guys from Interlok made a device driver in order to defeat Winice. Tpkd.vxd is a part of an InstallShield protection. In this document I will describe only the vxd part of this protection, the rest is on you.

Tools required

Winice, IDA, FileMon, Exespy, some VxD information :- Iczelion's VxD tutorials, Win98DDK, some hardware info about I/O ports.

Target's URL/FTP

www.installshield.com /*get the pwd for installation*/, www.microsoft.com, www.intel.com

Program History

InstallShield - when you need to make an installer for your program. I haven't seen a better program.

Essay

1. look around.

I started the debug session by loading the program. I hit CTRL+D, typed the BMSG XXX ... then a restart. Wow. Trap for Winice. Next I tried FileMon and Exespy. Worked! I found vl.vxd and tpkd.vxd. Both are dynamically loaded. Tpkd.vxd is loaded via CreateFileA. So I put the breakpoint on the control of the VxD. First of course I did bpx CreateFileA.

2. The main problem.

So we put a bpx on the control procedure of tpkd.vxd. Do it carefully! Otherwise you have to reboot.

C000693A PUSH EAX ; place the bpx before the CLI instruction
C000693B PUSHA
C000693C CLD
C000693D PUSHF
C000693E CLI
C000693F CMP ds:dword_C0002400, 0

To do this properly put bpx on CreateFileA or DeviceIoControl. After Winice informs you that tpkd module is loaded do the vxd command and find the control dispatch address. After Winice pops up step a little inside the vxd. When I flew through this piece of code I found something interesting :-

C0000AAA PUSH EBP
C0000AAB MOV EBP, ESP
C0000AAD SUB ESP, 20h
C0000AB0 PUSH EBX
C0000AB1 PUSH ESI
C0000AB2 PUSH EDI
C0000AB3 MOV [EBP+var_C], 88h
C0000AB7 PUSH EBX
C0000AB8 PUSH DX
C0000ABA PUSH AX
C0000ABC LEA EBX, loc_C0000AD5
C0000AC2 XOR BYTE PTR [EBX], 0BEh ; byte decryptor
C0000AC5 JMP short $+2
C0000AC7 MOV DX, 38h
C0000ACB MOV AX, 80h
C0000ACF PUSHFW
C0000AD1 CLI
C0000AD2 SHL DX, 1

C0000AD5 PUSH EAX ; out 70,80 - disable the NMI signal.
C0000AD6 XOR BYTE PTR [EBX], 0BEh
C0000AD9 LEA EBX, loc_C0000AE8
C0000ADF XOR BYTE PTR [EBX], 8Ch ; as above
C0000AE2 JMP short $+2
C0000AE4 JMP short $+2
C0000AE6 INC DX

C0000AE8 PUSHA ; in ax,71 ; ax=0
C0000AE9 MOV AH, AL
C0000AEB MOV AL, 0
C0000AED DEC DX
C0000AEF XOR BYTE PTR [EBX], 8Ch
C0000AF2 LEA EBX, loc_C0000AFF
C0000AF8 XOR BYTE PTR [EBX], 8Fh
C0000AFB JMP short $+2
C0000AFD JMP short $+2

C0000AFF POPA ; out 70,00
C0000B00 POPFW
C0000B02 MOV BYTE PTR [EBP+var_8], AH

After this again interesting piece :-

C0000B3D MOV DWORD PTR [EAX], 4245C8Bh ; what's this?
C0000B43 MOV EAX, [EBP+var_20]
C0000B46 ADD EAX, 4
C0000B49 MOV [EBP+var_20], EAX
C0000B4C MOV EAX, [EBP+var_20]
C0000B4F MOV DWORD PTR [EAX], 66D23366h
C0000B55 MOV EAX, [EBP+var_20]
C0000B58 ADD EAX, 4
C0000B5B MOV [EBP+var_20], EAX
C0000B5E MOV EAX, [EBP+var_20]
C0000B61 MOV DWORD PTR [EAX], 0E2C16642h
C0000B67 MOV EAX, [EBP+var_20]
C0000B6A ADD EAX, 4
C0000B6D MOV [EBP+var_20], EAX
.....
C0000B90 CALL EAX ; call the above placed code

C0000B92 POP ECX
C0000B9A CALL sub_C000481F
C0000B9F MOV [EBP+var_4], EAX
C0000BA2 PUSH offset loc_C0000950
C0000BA7 PUSH 1
C0000BA9 MOV ECX, offset byte_C0000130
C0000BAE CALL sub_C00047A3
C0000BB3 CALL [EBP+var_4] ; call what?

I stepped inside the CALL [EBP+var_4]. Tpkd was fiddling with Winice, read my interrupt descriptor and placed some strange values inside debug registers. This was too much! At third or fourth time you reach the control comes the restart. After I put the whole problem on the message board. Spath gave me some hints. Thanks!. The restart was done through the keyboard controller /*out 64,fe*/. Nice piece of code :-

C000451E PUSH EBP ; never come back
C0004528 MOV DX, 32h ; DX=32 - hide the value!
C000452C SHL DX, 1 ; DX*2=64 - the keyb. controller
C000452F IN AL, DX ; AT Keyboard controller 8042.

C000453A MOV AL, 0FEh
C000453C OUT DX, AL ; AT Keyboard controller 8042.

I was missing some info so I downloaded Intel's keyboard controller manual. It doesn't matter which one. It should be 8042 compatible. I found the 8XC51SL/LOW VOLTAGE 8XC51SL's datasheet. It says :-

"Power Down mode can only be exited via a reset. This reset may occur either from the RST pin, or an internally generated reset. See the 51SL Hardware Description (Order No. 272268) for a detailed description of this reset".

Internal reset. I patched the vxd immediately - location C000451E to RET. It worked with a PAGE fault. Pretty complicated, huh? - Did you find this text? Pretty joke. No, it wasn't the stack problem. When I single stepped the first time, the program worked! So it's the NMI problem. Try jumping over the in and outs in subroutine C0000AAA. It fails when you reach this :-

C0000BA9 MOV ECX, offset byte_C0000130
C0000BAE CALL sub_C00047A3
C0000BB3 CALL [EBP+var_4] ; page fault inside
C0000BB6 POP EDI
C0000BB7 POP ESI
C0000BB8 POP EBX
C0000BB9 LEAVE
C0000BBA RETN

At this point I tried a newbie trick - changing the C0000BB3 location to NOP's. Man! It works!, the tpkd is defeated.

Final Notes

Programmers, don't make jokes!. You just give hints to the cracker where not to search. The patch is pretty easy, huh?.

Special thanks to Spath who gave me some useful hints.

PS: I think there are still some traps left, so be careful.

macilaci