Log in

View Full Version : int 20 (hinte's crackme #6)


ZaiRoN
February 5th, 2002, 13:22
hi to all,
it's possible detect sice using this piece of code:

int 20 vxdcall vxdldr_getdevicelist
xor ebp, ebp
mov ebx, [eax+5]
cmp ebx, 0xC0000000
pushfd
and dword ptr [esp], 01

maybe i'm wrong but think that the last three instructions are potentially dangerous. any hint?


thanks in advance,
ZaiRoN

Kayaker
February 5th, 2002, 17:32
Hi ZaiRoN

In what way do you mean dangerous? This is one pretty slick code snippet.

I think I'm going to leave this one up to the user to explore, but basically what is returned in [EAX+05] is the VxD_Desc_Block structure (DDB or Device Description Block) for the most recent VxD in the list of devices maintained by VXDLDR.

The CMP EBX,C0000000 statement is the amazing one in that it returns the Device_ID for Softice in esp-4. [WRONG, DUMMY!!, see later comment on how Numega may have chosen their Device_ID...] The pushfd statement is simply accessing that stack parameter. I assume there's a conditional jump statement somewhere later on.

Are you at liberty to say where you found this code? Like some nasty virus or cryptor we may want to defend ourselves against? Some might consider this code potentially dangerous...

Kayaker

ZaiRoN
February 5th, 2002, 18:46
Hi Kayaker,

first of all i'd like to thank u for the reply

Quote:
I assume there's a conditional jump statement somewhere later on.

perfect! you have hit the centre of the target
the problem is that jump (absolute, non conditional!).

you can found this code snippets in the hinte's crackme#6 (download it from the crackme site).

ZaiRoN

ps. maybe it would be possible to move the discussion to the mini project area...

Kayaker
February 6th, 2002, 03:34
OK ZaiRoN, this is one hell of a crackme, it might make one hell of a project. I'll up the target file here as well.

To start with, I have to ask if you managed to break into the crackme to start tracing. Loader32 and Icedump failed to break at WinMain. I was able to start the crackme with Frogsice, which reported there were various Code 00 attempts being made to detect Softice. If I tried to use hmemcpy to monitor the s/n being inputted I got some lovely BSOD's. Needless to say I haven't progressed on the keygen routine or even found the SI detection code you listed.

I did find a few interesting things out though because I was able to break at WinMain and start tracing in a traditional way by cheating and using my own loader, part of the Softice backtrace disassembler proggy Clandestiny and I are working on. It uses a dll injection technique that allows you to *jump* into the program OEP. No way to detect it since it's non-traditional, so no way to prevent it ;-)

I was able to put together a few SI backtraces of the actual code sequence the program starts up with. There was much zeroing of code bytes every so often, so I had to break up the backtraces and nop out the actual REPZ STOSB lines so the disassembler could disassemble the results properly. Anyway, here is some of the output I got from our tool (TraceDump). The numbers on the left are the trace output line numbers and will vary depending on where I broke up the backtracing and snipped the code. It doesn't progress towards the keygen at all, but it does show some interesting protection code. Not sure exactly what all the code is doing, but there's some interesting snippets nonetheless

Remember this is the *actual* sequence of code executed, resolved from any SMC, because this is what the Softice backtrace is actually recording, our tool just disassembles those addresses which are stored in the backtrace buffer, while the program is loaded in memory. It starts at the OEP of 403E8F and there is much playing with the stack to produce valid jump addresses, here's a small snippet:

Code:
01 403E8F 688DE7F6C681 PUSH DWORD C6F6E78D ;OEP
02 403E94 8104241657493983 ADD DWORD [ESP], 39495716
03 403E9B 83C404FF ADD ESP, BYTE +4
04 403E9E FF6424FCEA JMP NEAR [ESP-4] ; jmp 403EA3
05 403EA3 BB1D2216B881 MOV EBX, B816221D
06 403EA8 81C32AF6294868 ADD EBX, 4829F62A
07 403EAE 689CE7F6C681 PUSH DWORD C6F6E79C
08 403EB3 8104242657493983 ADD DWORD [ESP], 39495726
09 403EBA 83C404FF ADD ESP, BYTE +4
0A 403EBD FF6424FCEA JMP NEAR [ESP-4] ; jmp 403EC2
0B 403EC2 5150 PUSH ECX
0C 403EC3 5033 PUSH EAX
0D 403EC4 33C0B9 XOR EAX, EAX
0E 403EC6 B942000000BF MOV ECX, 42
0F 403ECB BFC5E5675981 MOV EDI, 5967E5C5
10 403ED0 81EF36A7275990 SUB EDI, 5927A736
11 403ED7 9058 NOP
12 403ED8 5859 POP EAX
13 403ED9 59FF POP ECX
14 403EDA FFD368 CALL EBX ; call 401847
15 401847 5B68 POP EBX
etc.


Notice the NOP at 403ED7 (should actually be 2 nops). This is the first REPZ STOSB statement which normally would have zeroed out the previous code. I nopped it out to continue producing a usable trace for outputting. Eventually we'd like to do *real-time* dumping of the code so this wouldn't be necessary. So far nothing too interesting, I just wanted to show the general way the code works with all the stack jumps produced from adding a value to another value on the stack to produce a valid address.

...continued

Kayaker
February 6th, 2002, 03:45
The code continues on in this fashion for a while. There is a Structured Exception Handler (SEH) set up and an invalid opcode produced, but I wasn't able to break on the handler routine so I won't bore you with the code. The next interesting thing occurs here:

Code:

3C 4018EB 83C40483 ADD ESP, BYTE +4
3D 4018EE 83C404FF ADD ESP, BYTE +4
3E 4018F1 FF6424FCEA JMP NEAR [ESP-4]


Notice the two ADD ESP, BYTE +4 lines. If you allow both of them to execute you jump to Kernel32 code at address BFF8B560, which leads directly into an ExitThread call and the app never opens. It doesn't actually terminate, it's still listed as a 'task', but it never opens up. However, if you nop out one of the ADD lines, then the jump is instead back into valid program code. I'm not sure exactly what is happening here, whether the invalid opcode (F1) is being detected or what. The IDT hasn't been changed at this point so it's not a standard INT 6 invalid opcode hook or anything.

Anyhow, the code goes on to access the starting address of the GDT and pops it into EBX:
Code:

2F 4026CC 0F014424FE5B SGDT [ESP-2]
30 4026D1 5B33 POP EBX

Then it finds the LDT from the GDT address:

36 4026E8 0F00C024 SLDT AX
37 4026EB 24F803 AND AL, F8
; al = D0h
38 4026ED 03D868 ADD EBX, EAX
; add to GDT address
39 4026EF 685CCD16B981 PUSH DWORD B916CD5C
3A 4026F4 810424A759294783 ADD DWORD [ESP], 472959A7
3B 4026FB 83C404FF ADD ESP, BYTE +4
3C 4026FE FF6424FCEA JMP NEAR [ESP-4]
3D 402703 8A6B078A MOV CH, [EBX+7]
; ch = 80
3E 402706 8A4B04C1 MOV CL, [EBX+4]
; cl = 0
3F 402709 C1E11068 SHL ECX, 10
; ecx = 80000000

ECX is now 80000000, close to the LDT address...

40 40270C 68AE5748C881 PUSH DWORD C84857AE
41 402711 81042472CFF73783 ADD DWORD [ESP], 37F7CF72
42 402718 83C404FF ADD ESP, BYTE +4
43 40271B FF6424FCEA JMP NEAR [ESP-4]
44 402720 668B4B028D MOV CX, [EBX+2]
; cx = 3000

ECX is now 80003000, the start of the LDT (at least on my system, type 'ldt' in SI)

Then it writes into the LDT a valid call address. Note that an entry in the LDT, like the IDT, takes up two dwords (64-bits), and is laid out in a 'table' format like this:

-------------------------------------------
016F:80003008 34C7 0028 EC00 0040
; Icedump screendump of my LDT after the crackme code writes to it

34C7h are bits 31...16 of the address
0028h is the Target Segment Selector
EC00 is a bunch of flags we don't care about
0040h are bits 15...0 of the address

So the real address coded here is 28:004034C7
-------------------------------------------

...continued

Kayaker
February 6th, 2002, 03:45
And the LDT writing routine in the code:
Code:

Stores the Least Significant Word of the call address (34C7h):

45 402724 8D7908FC LEA EDI, [ECX+8]
46 402727 FC8B CLD
47 402728 8BC666 MOV EAX, ESI
48 40272A 66AB68 STOSW

Stores the Segment Selector and the bullshit flags we don't care about:

4D 402740 B8280000ECAB MOV EAX, EC000028
4E 402745 AB0F STOSD

Stores the Most Significant Word of the call address (0040h):

4F 402746 0FA4F01068 SHLD EAX, ESI, 10
...
54 40275E 66AB61 STOSW


And finally this address, which the proggy cleverly
inserted into the LDT is called:

8C 40284C 9A000000000F0051 CALL F:00000000

which is to 28:004034C7. Since this uses the segment selector normally reserved for vxds, I couldn't use TraceDump to output trace from it because the SI backtrace BPR doesn't allow it, and Icedump /screendump similarly failed. So you'll have to take my word for it that the code is:
Code:

28:4034C7 PUSH 6B3CAE82
28:4034CC SUB DWORD PTR [ESP], 6AFC8B9E
28:4034D3 ADD ESP, 4
28:4034D6 CALL [ESP-4]
28:4034DA RETF

After returning to the regular segment selector the code continues on (seemingly forever, sigh):
Code:


8D 402853 5150 PUSH ECX
...
96 40286B C3EA RET

Actually, you don't have to take my word for it. There is no breakpoint detection at least in this part of the code, so if you set a BPM on any of the addresses I gave above (using your own normal CS selector) you *should* break freely. i.e.
BPM 167:4026CC X
should get you at where the GDT is read:
4026CC 0F014424FE5B SGDT [ESP-2]

Anyway, I'll hope you'll forgive me for going off on a tangent, I just enjoy ferreting out sneaky little code snippets like this. If we're to protect ourselves from questionable code practices (viral perhaps), then we need to start by being aware of them.

Cheers,
Kayaker

+SplAj
February 6th, 2002, 06:45
Hi Kayaker

thanx for the indepth analysis. those SEH redirections are the 'vogue' thing right now

I d/l said target and of course it won'r run on WinNT/2K platform. Interesting point is no IAT or IT in header ?

Is it packed or just re-aligned very aggressively to 0x200 ?

I don't have Win98 here to analyze further...........

Spl/\j

ZaiRoN
February 6th, 2002, 08:43
HI Kayaker

i agree with +SplAj, your analysis sounds good

my initial goal is to study how the program detect the sice. no keygen for the moment...maybe another mini project

the serious thing:
fundamentally i have found 3 kinds of protection against sice: seh, ldt and the int20.

1) seh:
here is how it installed the seh:

401876: push 49975D87
40187B: sub dword ptr [esp], 49572959
401882: xor eax, fs:[ebx]
401885: push eax
401886: mov fs:[ebx], esp

after the sub, [esp]=40342E. 40342E is the handler u are looking for
so, when you found the invalid opcode (at 4018BE) redirect the flow to the routine handler.

for the ldt i think you have just said everything..but i have a question for u:
Quote:
8C 40284C 9A000000000F0051 CALL F:00000000
Since this uses the segment selector normally reserved for vxds

it's necessary to use this segment?
when u are in the call above try to redirect the flow to the 4034C7 of the original segment. some lines and you'll find the int20 code...

for +SplAj:
Quote:
Is it packed or just re-aligned very aggressively to 0x200 ?

i don't know...i think it's certainly re-aligned.

all for the moment, i think that there will be very much to learn from this crackme

ZaiRoN

ZaiRoN
February 6th, 2002, 15:32
hi Kayaker

Quote:
8C 40284C 9A000000000F0051 CALL F:00000000


maybe i'm wrong but i think that hinte wants to bring us in the wrong way forcing the flow in the segment reserved for the vxd.
if you try to jump to 4034C7 (in the original segment) and step a little you'll found a very interesting decryption routine (4022F8/402354).
after that routine the bytes from 403DD5 to 403E8E turn out very intersting. i've found things like user32.dll, Getmodulehandle, MessageBox etcetc...
maybe it's a good thing

ZaiRoN

ZaiRoN
February 8th, 2002, 08:00
hi,
someone is working to the project?

i have a little question for u:
Quote:
The CMP EBX,C0000000 statement is the amazing one in that it returns the Device_ID for Softice in esp-4.

if Softice is not in the device list which it's the value of ebx?

ZaiRoN

Kayaker
February 8th, 2002, 15:44
Hi ZaiRoN

I'm definitely still working on this as I get the chance. Your last posts were very helpful! Redirect the LDT call using a regular code segment and sure enough lots of interesting things appear. Now we know where the IT went to

Strange how the jump after the Int 20 call goes to address 000282. Actually I got the exact same address if I tried to trace into the jump that was in the 0028 segment LDT Call F:00000000 . You can F10 step over this call, but just don't try tracing into it without redirecting it into a regular code segment.

BTW, this funny looking call can be understood by typing 'LDT' in Softice before and after you've run the crackme for the first time and you see how it's created a Ring3 gated call:
Code:

LDTbase=80003000 Limit=3FFF
0004 Reserved 00000000 00000000 0 NP
000F CallG32 0028:004034C7 3 P
0014 Reserved 00000000 00000000 0 NP


As for what's happening on that VXDLDR_GetDeviceList Int 20 call:

I don't think the value of EBX itself changes if SI isn't loaded, it still seems to be the DDB of the most recent VxD. The reason I say this is that I had inserted the code you initially posted into my own vxd code, and the value in mov ebx, [eax+5] was the DDB of my own vxd, which was easy to recognize from the DDB_Name field in the DDB structure.

Here's the output and structure just for reference. Note that there seems to be more than one define of the VxD_Desc_Block (DDB) structure around, this one is from vmm.inc and seems to be comparable to what you see in Softice.
Code:

EBX=D56A78F0
0030: D56A78F0 C01677D8 0000040A 80020001 43415254 .w..........TRAC
0030: D56A7900 504D5544 80000000 CAA05730 00000000 DUMP....0W......
0030: D56A7910 00000000 00000000 00000000 00000000 ................
0030: D56A7920 00000000 00000000 00000000 D56EBD00 ..............n.
0030: D56A7930 00000050 52737631 52737632 52737633 P...1vsR2vsR3vsR

VxD_Desc_Block STRUC
DDB_Next DD ?
DDB_SDK_Version DW DDK_VERSION
DDB_Req_Device_Number DW UNDEFINED_DEVICE_ID
DDB_Dev_Major_Version DB 0
DDB_Dev_Minor_Version DB 0
DDB_Flags DW 0
DDB_Name DB " "
DDB_Init_Order DD UNDEFINED_INIT_ORDER
DDB_Control_Proc DD ?
DDB_V86_API_Proc DD 0
DDB_PM_API_Proc DD 0
DDB_V86_API_CSIP DD 0
DDB_PM_API_CSIP DD 0
DDB_Reference_Data DD ?
DDB_Service_Table_Ptr DD 0
DDB_Service_Table_Size DD 0
DDB_Win32_Service_Table DD 0
DDB_Prev DD 'Prev'
DDB_Size DD SIZE(VxD_Desc_Block)
DDB_Reserved1 DD 'Rsv1'
DDB_Reserved2 DD 'Rsv2'
DDB_Reserved3 DD 'Rsv3'
VxD_Desc_Block ENDS

------------------------------------------------

I had said that the CMP EBX,C0000000 statement returns the Device_ID for Softice in esp-4 because, well because it seemed to, id 202 kept appearing there. But I've just been noticing sometimes a slightly different return value as well under different conditions. I wouldn't mind if someone could confirm this.

The real question is what Device_ID is returned if SI isn't loaded, which I'm sure is what you really meant Zairon. I'm going to try to test this later tonight by passing that value in esp-4 via DeviceIOControl and outputting it to a MessageBox.

BTW, for those wanting to mess with this, an easy way to get into the code is to use Icedump with /PROTECT on. This will break when the GDT gets accessed for the 1st time. Turn protect off and you can start tracing. Not to worry, any BSOD's aren't harmful and don't reboot, just refresh with F5. You can change the LDT segment selector in memory to redirect jumps simply by changing the 0028 to your own CS.

Kayaker

ZaiRoN
February 9th, 2002, 06:15
Hi Kayaker,

your last post has made me think a little bit. in particular a single phrase:
Quote:
I don't think the value of EBX itself changes if SI isn't loaded

that's the point! i asked in another forum if it's possible detect softice using this method (int20blablabla); this is the (translate badly from italian to english...sorry) explanation given by Kill3xx (thanks a lot):

"the services of the VxD loader are to appanage of the dynamics (loadable) vxd.. and consequently the device_info list (and the ddb) not includes vxd loaded statically or "dynamically" by the vmm at the boot..."

so, the question is: why use this function??? which it is the sense??? is this only a trick to gain the r0 mode ?!?!!

another thing: i've given a look to the code that follows the damned jump. there's a little routine that slides entire the ddb. it will be another trick to bring us on the wrong way or ...something else

bha...

that's all friend,

ZaiRoN

Kayaker
February 9th, 2002, 20:18
OK, I see what you mean Zairon, VxDCall VXDLDR_GetDeviceList is only used for dynamically loaded vxds, and I found that VMMCall VMM_GetVxDLocationList is used for statically loaded vxds:

Code:

VMMCall VMM_GetVxDLocationList
jz ErrorHandler
mov [TableAddress], eax
mov [VxDCount], edx
mov [TableSize], ecx

Returns the address of the VxD location list in EAX,
returns the count of VxDs in EDX, and
returns the list size (in bytes) in ECX.
Uses EAX, ECX, and EDX.

Returns the address of the VxD if the function
succeeds; otherwise, sets the zero flag.
The VxD location list is a packed array of variable
length Device_Location_List structures.


The Device_Location_List structure will similarly give you a linked DDB list for statically loaded vxds:

Code:

Device_Location_List STRUC
DLL_DDB DD ?
DLL_NumObjects DB ?
DLL_ObjLocation DB SIZE ObjectLocation * 1 DUP (?)


I threw this in some code and by following the DDB_Prev field of the VxD_Desc_Block confirmed the static vxds I had loaded - VMM, CSHOOK, SHELL, VFBACKUP,... Eventually I assume I would have hit SIWVID and WINICE but I didn't want to scroll through my 56 vxd entries to find it.


So, with these 2 calls, VMMCall VMM_GetVxDLocationList and VxDCall VXDLDR_GetDeviceList, you can get a list of all the static and dynamically loaded vxds on your system.

In fact, this is how Softice generates the list you see when you type 'vxd'. You can find these addresses in winice.exe here:

Code:

C005E004 mov esi, offset aVxdNameAddress
; "VxD Name Address Length Seg ID "...
C005E009 call sub_C0018A8A
...
C0082FD2 VxDcall VXDLDR_GetDeviceList
...
C008E6F7 VMMcall VMM_GetVxDLocationList


As a sideline, you ever used IceClimber by Trapflag? It allows you to set breakpoints within Softice itself. Makes for some interesting bedtime tracing I haven't tried it with this crackme, but it *may* allow you to set bp's within those 0028: code segments as well, just a thought.


So you're right about the use of VXDLDR_GetDeviceList, why use this function if all it returns is the most recent dynamically loaded vxd in EBX? But tell me, if you type 'd ebx' in SI what vxd name do you see? If you've got Icedump loaded, what name do you see?... If you follow the DDB_Prev field back 2 or 3 links does this not look like the (dynamic) list you get with 'vxd' in SI?

I still don't know how this relates to what happens after the VXDLDR_GetDeviceList call or what is happening on the stack though, and I haven't been able to get past that jmp esp-4 statement yet.

Back to the drawing board...

Kayaker

Kayaker
February 10th, 2002, 07:46
Hi

Just a quick note to set the record straight. I see I was *way* off base thinking that this code had anything to do with the Device_ID for Softice. It was just (bad) luck that I first saw the value of 0202h appearing on the stack. This *is* actually the ID for winice, which is what threw me at first, but has nothing to do with that.

Instead this is simply the value of the Flags register, and changes on any command that changes the flags. Check the Art of Assembly Language Chapter 6 or the Intel Developers Manual 1 under EFLAGS for a detailed explanation. The latter states that "When a call is made to an interrupt or exception handler procedure, the processor automatically saves the state of the EFLAGS registers on the procedure stack", explaining its presence there.

The flags you see in the Softice Register window and the hex value you see on the stack can be understood by changing the value to binary and following the bit pattern.

Bit 0 - C (Carry flag)
Bit 1 - Reserved, set to 1
Bit 2 - P (Parity flag)
Bit 3 - Reserved, set to 0
Bit 4 - A (Auxiliary carry flag)
Bit 5 - Reserved, set to 0
Bit 6 - Z (Zero flag)
Bit 7 - S (Sign flag)
Bit 8 - Trace (Trap) flag, not shown by Softice
Bit 9 - I (Interrupt flag)
Bit 10 - D (Direction flag)
Bit 11 - O (Overflow flag)
Bits 12-31 not shown by Softice

So the value of 202h I just happened to see (binary 001000000010) corresponded to the flags being set like this (remember Bit 1 is set to 1 by default):
o d I s z a p c

If it was 206h (001000000110) the flags would be:
o d I s z a P c

You can actually test this in the crackme code (or your own vxd verion) by changing the flags with 'R FL <flag>' and seeing how the value on the stack changes.


Knowing this we can start to look at what the rest of the code is doing.
Code:

int 20 vxdcall vxdldr_getdevicelist
xor ebp, ebp
mov ebx, [eax+5]
cmp ebx, 0xC0000000
pushfd
and dword ptr [esp], 01


- mov ebx, [eax+5]
we know moves the VxD_Desc_Block structure (DDB or Device Description Block) for the most recent dynamically loaded VxD into ebx.

- cmp ebx, 0xC0000000
is something I have seen documented in some viral code, followed by a jc @@next_vxd (Jump if Carry, follow DDB_Next to next VxD_Desc_Block, repeat loop).

- pushfd
- and dword ptr [esp], 01
pushes the EFLAGS register onto the stack and ANDS the value with 01, checking the Carry flag.

Now the CMP statement modifies the Carry flag in the following way:

cmp ax, bx
C: The carry flag is set after a cmp operation if subtracting bx from ax requires a borrow. This occurs only when ax is less than bx where ax and bx are both unsigned values.

So I would hazard this code may be checking for what vxds are loaded. If it's using the DDB_Next field as in the viral example, then you can trace this yourself from the initial DDB obtained and see that you can get into the *statically* loaded vxds as well.

There is further code going on after this, including a CDQ division, but I haven't looked at it yet in this new light. All the viral coders are probably snickering behind their hands right now, but that's OK, either snicker or help.

Cheers,
Kayaker

ZaiRoN
February 10th, 2002, 11:43
hi,

as always your posts were very interesting
sorry me but i can't understand the role of the flags. maybe i'm wrong but your are saying that this code:
Code:

cmp ebx, 0xC0000000
pushfd
and dword ptr [esp], 01

is used for sliding all the vxds (stat. or dyn.)?


for the rest:
Quote:
If it's using the DDB_Next field as in the viral example...


i think we have read the same article
perhaps it is this:
Code:
call vxd ;VXDLDR GetDeviceList
@@next:
mov ebx, [eax+5] ;VxD_Desc_Block *DI_DDB
sub ebx, 0C0000000h
jc @@next_vxd
lea ecx, [ebx+0C000000Ch] ;Name_0
cmp [ecx], 'DIPS' ;'SPIDER '
je @@patch
cmp [ecx], '9PVA' ;'AVP95 '
jne @@next_vxd


here is what the crackme is doing! i have take a look to the code beyond the "and dword ptr [esp], 01" and i have found something like that:

cmp [ecx], 'FILE'

try lo load filemon and run the crackme. you'll see what i'm saying

maybe something more tonight...

ZaiRoN

Kayaker
February 10th, 2002, 14:53
Hi Zairon,

Yep, we've been reading the same document

Code:

cmp ebx, 0xC0000000
pushfd
and dword ptr [esp], 01


is used to check the state of the Carry flag after the cmp. If ebx is less than C0000000, meaning you've gotten below Ring0 code where a DDB address is no longer valid, then the Carry flag is set. Pushfd pushes the EFLAGS value, or the state of all the flags, onto the stack and the AND statement tests the Carry Bit 0. If the Carry flag is set (esp=1), then esp becomes 1, if unset, 0.

You see this used later on as well several times for testing the Zero flag:
Code:

cmp [ecx], something
pushfd
shr [esp], 06 ; shift the Zero flag to the bit 0 position
and [esp], 01 ; test if it's set


You could also use the Bit Test (BT) commands to do the same thing, except that they modify the Carry flag themselves.

I didn't get any meaningful results from Filemon btw.
This whole sequence of code is looking for a particular vxd loaded, and it's pretty apparent what that vxd is. Try changing the name of 'FILE' in memory ([ecx])
cmp [ecx], 'FILE'
and see if the crackme doesn't open

As an aside, if the Device_ID of Softice is 202 and corresponds to the Interrupt flag being set:
202h (binary 001000000010)
o d I s z a p c
I wonder if some Numega programmer was having fun when they chose that as a Device_ID for sice?

Cya,
Kayaker

ZaiRoN
February 10th, 2002, 16:41
hi Kayaker,

OK! i have understood!

Quote:
This whole sequence of code is looking for a particular vxd loaded...and see if the crackme doesn't open


i have found the list of vxd but...the crackme doesn't open
what i have mistaken?

ZaiRoN

ZaiRoN
February 10th, 2002, 19:18
hi,

i answer myself: Kayaker, you're using icedump!

you're a lazy man the rule is: only softice! no other tools
i think i'll continue to study the rest of the program; maybe i'll find other interesting thing

bye,
ZaiRoN

Kayaker
February 10th, 2002, 21:17
LOL

- you must write a keygen
- no patching

I don't see any other rules

CoDe_InSiDe
February 11th, 2002, 02:52
Hi everyone,

Just a little side note, trace from the OEP of the program, then you'll see that he uses that "pushfd - and [esp], 01 etc...", or something similiar, very often for jump statements
Also (Like Kayaker mentioned) a lot in the rest of the program
It's actually the same as a "jz" for example

Ok, enough of my mumbling maybe i'll come back to this CrackMe

Cya...

CoDe_InSiDe

ZaiRoN
February 11th, 2002, 17:56
hi Kayaker,

doh! you're right...sigh...

btw, from your first post i've seen that you had tried to make a keygen. are u able to put bpx?
i think that the study of the rest of the code is "necessary"

see you soon,
ZaiRoN

Kayaker
February 12th, 2002, 01:40
Hi Zairon,

I've had a *little* bit of success on scoping out the s/n routine. What I did was to open the crackme with Icedump, but as we discussed above the crackme won't open unless you patch in memory the DDB entry for that vxd. I'm actually working on a protection against that 'vulnerability'. This affects not only the ICEDUMP driver but also SICE and SIWVID in a similar manner. This is sort of an extension of the Code 09 VMMCall Get_DDB method of detection discussed in the Frogsice doc, just a different way of using the DDB. I've got the basic protection completed and will probably release it in a few days after I polish it up and have some fun with it In the meantime you need the "fix" that manually.

There may be other ways around this or you can get the crackme open with Frogsice itself I think. Anyway, I was able to break on inputting a Name using hmemcpy. At 402D9D is a CALL [ESP-4] which is the hmemcpy call itself which monitors what you enter as a name character by character. At 402DB5 there is a CMP EAX, 4 ; the minimum length of name allowed, and it tests the result of the cmp with that famous routine
pushfd
and dword ptr [esp], 01
You're right CodeInside, this is used everywhere!

Then it takes the last 2 characters of your name (in ESI) and goes into this routine, the output I generated from a backtrace:
Code:

18 402E08 66031E66 ADD BX, [ESI] ; start of loop
19 402E0B 6603CBC1 ADD CX, BX
1A 402E0E C1C10B68 ROL ECX, B
1B 402E11 68B993CC7481 PUSH DWORD 74CC93B9
1C 402E16 8104246C9A738B83 ADD DWORD [ESP], 8B739A6C
1D 402E1D 83C404FF ADD ESP, BYTE +4
1E 402E20 FF6424FCEA JMP NEAR [ESP-4] ; 402E25
1F 402E25 2BCB81 SUB ECX, EBX
20 402E27 81F14513000068 XOR ECX, 1345
21 402E2D 68D340DD7581 PUSH DWORD 75DD40D3
22 402E32 8104246EED628A83 ADD DWORD [ESP], 8A62ED6E
23 402E39 83C404FF ADD ESP, BYTE +4
24 402E3C FF6424FCEA JMP NEAR [ESP-4] ; 402E41
25 402E41 C1C90348 ROR ECX, 3
26 402E44 489C DEC EAX
27 402E45 9CF7 PUSHF
28 402E46 F71424C1 NOT DWORD [ESP]
29 402E49 C12C240683 SHR DWORD [ESP], 6
2A 402E4D 8324240150 AND DWORD [ESP], BYTE +1
2B 402E51 5052 PUSH EAX
2C 402E52 5299 PUSH EDX
2D 402E53 99B8 CDQ
2E 402E54 B8EE25E8CF35 MOV EAX, CFE825EE
2F 402E59 3561DA1730F7 XOR EAX, 3017DA61
30 402E5E F764240805 MUL DWORD [ESP+8]
31 402E62 05DA0858302D ADD EAX, 305808DA
32 402E67 2D61DA173089 SUB EAX, 3017DA61
33 402E6C 894424085A MOV [ESP+8], EAX
34 402E70 5A58 POP EDX
35 402E71 5883 POP EAX
36 402E72 83C404FF ADD ESP, BYTE +4
37 402E75 FF6424FCC3 JMP NEAR [ESP-4] ; 402E08
Loops to above 4 times
38 402E08 66031E66 ADD BX, [ESI]
39 402E0B 6603CBC1 ADD CX, BX
etc...

When it's done with this loop, JMP NEAR [ESP-4] points to 402E7E instead of back to 402E08, and the loop is finished:
Code:

96 402E72 83C404FF ADD ESP, BYTE +4
97 402E75 FF6424FCC3 JMP NEAR [ESP-4]
98 402E7E 05CAA7F62968 ADD EAX, 29F6A7CA
...

From here the code seemed to go into GetDlgItemTextA, but as a direct jump not an API call, so I don't think you can set a break on it. Not sure how that's used. There's lot's of other code in there, the loop I listed above seems to get called again, perhaps in response to GetDlgItemTextA.

You can enter a s/n and follow its course in a similar manner, but this seems to get into some crypto/hashing stuff, which I know little about. I've got a shitload of trace output (like about 4000 lines) so I don't know wtf it's doing to be perfectly honest Maybe I could just dump it all into a keygen and see if it works, heh.

That's it for now, I think I'll go back to coding. If you can at least break on that Hmemcpy 402D9D CALL [ESP-4] line, or the start of the loop I listed (with your name in ESI), then you should be at a good stage to start tracing.

Good Luck,
Kayaker

ZaiRoN
February 12th, 2002, 09:39
hi,

Quote:
From here the code seemed to go into GetDlgItemTextA, but as a direct jump not an API call, so I don't think you can set a break on it. Not sure how that's used

this is right. the s/n isretrieve using GetDlgItemTextA in this way:
402EE8: call [esp-04]
enter the call and after few lines:
401164: jmp [ebx+10] ; jump to the code of GetDlgItemTextA

where ebx points to the references to the used apis.
the s/n must be 8 chrs.
much of code to explore....

cya..
ZaiRoN

the analyst
February 18th, 2002, 16:50
hello,

Quote:
Originally posted by Kayaker
The code continues on in this fashion for a while. There is a Structured Exception Handler (SEH) set up and an invalid opcode produced
then the jump is instead back into valid program code. I'm not sure exactly what is happening here, whether the invalid opcode (F1) is being detected or what. The IDT hasn't been changed at this point so it's not a standard INT 6 invalid opcode hook or anything.


just to let you know, this is not an invalid opcode.
In fact F1h is the undocumented opcode for int 1.
this is a not so known trick to detect tracing.

start:

xor eax,eax

push offset ExceptionHandlingFunction
push dword ptr fs:[eax]
mov fs:[eax], esp

db 0f1h ; undocumented INT 1

push 0 ; Exception not catched, beeing debugged
push offset traced ; Gotcha!
push offset traced
push 0
call MessageBoxA

; some nasty code couble be here
; or some fake routines eventually.

push 0 ; Exit to win
CALL ExitProcess


ExceptionHandlingFunction:

push 0
push offset exception ; im not being traced
push offset exception
push 0
call MessageBoxA

push 0 ; Exit to win
CALL ExitProcess

this detect revirgin tracer, wdasm tracer and many other.
I know this trick for some times already ;-)


just my two cents, hope it helps.

the analyst / HERT

Kayaker
February 19th, 2002, 23:54
Hi

Thanks for the info analyst ;-) I've since found out this is indeed an old largely undocumented form of the INT1 Single Step Trace Exception known as ICEBP. (Largely undocumented by Intel at least, but a search for 'ICEBP' yields a lot of info, i.e. h*tp://x86.ddj.com/secrets/opcodes/icebp.htm)

I *think* I see what's going on here, but anyone please clarify if I'm wrong, I'm still absorbing CPU architecture and Intel docs to get a better understanding. Normally if you are single step tracing (or using the SI backtrace feature), Softice clears the trace (T) flag in the EFLAGS register, so that the regular INT01 handler is not called. If this trace bit is clear, the instructions are executed without interruption.

So when this errant undocumented INT1 is stepped over (traced), it continues into the "bad boy" code. However, if you weren't single step tracing (and the Trace flag was set), then the SEH (the "good boy" code) that was previously set up would be called and you would continue on unmolested.

I'm still a little confused in how Softice behaves versus "other" debuggers in terms of this trace flag. According to http://www.woodmann.net/fravia/civetta.htm one way to detect SI is:

-----------------------------------------------------------------
4. by using the TRAP flag, one can use the single stepping feature to
call a protection routine (e.g. a decryptor). The problem is, that
during single stepping SOFT-ICE clears the TRAP flag for the V86 task
and will neither execute nor step into the INT01 handler of the
V86 task. Many schemes use this trick.
-----------------------------------------------------------------

OK, so this is where I got that the Trace (Trap) flag is cleared during single step tracing, and this is what this undocumented INT1 trick is taking advantage of. However, according to Art of Assembly Language Ch.6 (or the Intel docs):

----------------------------------------------------------------
The trace flag enables or disables the 80x86 trace mode. Debuggers (such as CodeView)
use this bit to enable or disable the single step/trace operation. When set, the CPU interrupts
each instruction and passes control to the debugger software, allowing the debugger
to single step through the application. If the trace bit is clear, then the 80x86 executes
instructions without the interruption.
----------------------------------------------------------------

In this case it seems to indicate that when the Trace flag is *set*, control is passed to the debugger "allowing the debugger to single step through the application". It just seems to indicate that there is an inherent difference in how Softice operates versus "other" debuggers, unless I'm misinterpreting all this.

Nothing I can't live with of course, it's just a question that came to my mind while trying to understand exactly what's going on. In any case you can certainly *see* the effect of this trick. If you set a bpm breakpoint on the address of the exception handler (good boy routine), which as Zairon said was at 40342E, Softice will break on it if you just execute the program. However if you try tracing over that INT1 (Trace flag cleared?) or use a Backtrace (based on BPR), then it won't break and you'll end up continuing on into the bad boy code.

The output from our Backtrace disassembler actually shows this bad boy sequence (pretty much as you see it in the Softice window anyway), but the difference is that the disassembler (based on the NASM disassembler) records the F1 opcode properly as an INT1, but Softice itself (as you'd see with SHOW) records the backtrace disassembly of 0xF1 as INVALID. Seems Numega never added support for some undocumented opcodes...

Code:

SEH:
23 401876 68875D9749 PUSH DWORD 49975D87
24 40187B 812C2459295749 SUB DWORD [ESP], 49572959
25 401882 643303 XOR EAX, [FS:EBX]
26 401885 50 PUSH EAX
27 401886 648923 MOV [FS:EBX], ESP
; handler routine now at 40342E (49975D87 - 49572959)
...

UNDOCUMENTED OPCODE + BAD BOY ROUTINE:
33 4018BE F1 INT1
34 4018BF 58 POP EAX
35 4018C0 680D620858 PUSH DWORD 5808620D
36 4018C5 810424C7B637A8 ADD DWORD [ESP], A837B6C7
37 4018CC 83C404 ADD ESP, BYTE +4
38 4018CF FF6424FC JMP NEAR [ESP-4]
39 4018D4 648903 MOV [FS:EBX], EAX
3A 4018D7 68382669F2 PUSH DWORD F2692638
3B 4018DC 810424B3F2D60D ADD DWORD [ESP], DD6F2B3
3C 4018E3 83C404 ADD ESP, BYTE +4
3D 4018E6 FF6424FC JMP NEAR [ESP-4]
3E 4018EB 83C404 ADD ESP, BYTE +4
3F 4018EE 83C404 ADD ESP, BYTE +4
40 4018F1 FF6424FC JMP NEAR [ESP-4]
; to Kernel ExitThread


Anyway, thanks again for the interesting tip

Regards,
Kayaker

the analyst
February 20th, 2002, 06:42
heya

Quote:
Originally posted by Kayaker
Hi

Thanks for the info analyst ;-) I've since found out this is indeed an old largely undocumented form of the INT1 Single Step Trace Exception known as ICEBP. (Largely undocumented by Intel at least, but a search for 'ICEBP' yields a lot of info, i.e. h*tp://x86.ddj.com/secrets/opcodes/icebp.htm)
set a bpm breakpoint on the address of the exception handler (good boy routine), which as Zairon said was at 40342E, Softice will break on it if you just execute the program. However if you try tracing over that INT1 (Trace flag cleared?) or use a Backtrace (based on BPR), then it won't break and you'll end up continuing on into the bad boy code.
Anyway, thanks again for the interesting tip
Regards,
Kayaker



This piece of code is actually an anti tracing code.
If you run the software without stepping in, it won't call
the bad boy code.
It is usefull to detect debuggers that single step thru the code
such as Wdasm's debugger etc..
Try my code and see how wdasm get owned
You can do the same with the trap flag.
But some better tracer, such as Revirgin don't get owned by
the trap flag, while they are bumfucked by that int 1 trick
Note that , you could use a standard int 1 instead of the F1h one.
It is too obvious then tho

Here comes the trap flag code :

start:

xor eax,eax

push offset ExceptionHandlingFunction ; exception handler
push dword ptr fs:[eax]
mov fs:[eax], esp

pushf
pushf
pop eax ; get the flag register
or eax, 100h ; and put the TF Trap Flag (Single Step)
push eax ; And then
popf ; Put it in the register flag
nop

push 0 ; Exception not catched! we are beeing debugged!
push offset trace ; Gotcha!
push offset trace
push 0
call MessageBoxA

; we should put some nasty code in here
; or go to some fake routines eventually.

push 0 ; Exit to win
CALL ExitProcess


ExceptionHandlingFunction:

push 0
push offset exception ; All is fine, im not being traced
push offset exception
push 0
call MessageBoxA

push 0 ; Exit to win
CALL ExitProcess


end start


It behaves like the F1's one, but don't fool all the debuggers..
If you step in with F10, you will go in bad boy code, else
you will get back in the good boy place
It is good to put such code in a name / serial scheme
Newbies, just keep tracing, don't even know wtf is the trap flag
and get fooled black and blue ;-)

My other 2 cents ;-)

regards,

The Analyst / HERT

evaluator
March 7th, 2002, 16:40
Hello, Kayaker!

I found, why SICE (&+ ICEDUMP) can't load
EXE.
Because in header 1st section's Virtual Offset is 00001057
Abnormal!
Correct it to 00001000 & all will OK.