Log in

View Full Version : Avoiding INT1 detection of SoftICE under WinXP


SiNTAX
September 23rd, 2002, 22:59
Does anybody have a tool or tip to avoid INT1 detection of softice (WinXP)?! As it stands now, SI just treats the INT1 as a NOP.. or if you use I1HERE it breaks but doesn't execute the exception handler.

Thought I'd ask, before trying to patch SoftICE myself...

evaluator
September 24th, 2002, 09:06
Yah!

In general you must NOT DO "F8" (single step) on this instruction & exception handler will work!

BTW, this is not subject for this forum.

SiNTAX
September 24th, 2002, 09:23
Quote:
Originally posted by evaluator
Yah!

In general you must NOT DO "F8" (single step) on this instruction & exception handler will work!

BTW, this is not subject for this forum.


Really? I thought (plain/unpatched) SI would just skip the instruction.

I'm almost certain SI handles the INT1 a bit differently than when no SI is present.

evaluator
September 24th, 2002, 11:12
I know about difference & how to...

SiNTAX
September 24th, 2002, 11:29
I'll just hook INT1 and check if the exception was caused by an INT1 instruction, if so.. pass it on to the old INT1 handler instead of giving it to SI.

Shouldn't be too hard to do..

evaluator
September 24th, 2002, 20:08
so happens without your "help"

SiNTAX
September 24th, 2002, 23:21
Quote:
Originally posted by evaluator
I know about difference & how to...


So do I now

8...4->C...5

evaluator
September 25th, 2002, 00:00
not enaf!
find ^DAEMON^ 's home page, download "sice detector" & make test.

Bye!

SiNTAX
September 25th, 2002, 00:18
'SICE_NOT_FOUND' is enough for me

^DAEMON^ 's "sice detector" doesn't detect my SoftICE when I use I1HERE ON and then 'X' when SI breaks.

But my new and improved version does..

evaluator
September 25th, 2002, 11:10
you not understand fully trick,
but this is because of not enauf implementation by ^DAEMON^!

I just upgraded his prog, so it will detect NTICE in 3 kind!!!

So I need ^DAEMON^'s permission for publish it

^DAEMON^,^DAEMON^! where are U!?

SiNTAX
September 25th, 2002, 11:30
I understand it perfectly.. don't worry

Anyway my original beef was with an SD executable, which uses INT1 as a first SI detection. Changing the exception code resolved the detection.. so problem solved..

But.. you speak of 3 methods.. I only count 2, so guess there's one more way. Feel free to share it.

1) eip +2
2) exception code
3) ?

evaluator
September 25th, 2002, 13:00
as already wrote: single stepping(F8,F10) on INT01.
This not implemented in "SiceDetector", so if you trace program in ntice, it "not founds".

also there is another easy detection for ntice

^DAEMON^
September 25th, 2002, 15:59
hi,

my page is currently down... i don't know when it will go online again...

u can release it of course

(btw. i don't know when i'll update my page the next time
i've other projects running currently)

^DAEMON^

evaluator
September 25th, 2002, 18:06
Hell_to_you DAEMON!

OK! Here is UPGRADED INT01_SICE DETECTOR.
1. Detects single step on INT01 instruction
2. Detects if INT01 is trap (so NTICE is here)

2-nd case self-intends error code kind (80000003 or C0000005), so I not included test for it.

BTW, I have only XP, so test it on W2k, nt..

SiNTAX
September 26th, 2002, 08:08
Might as well make it complete and add:

..to exception handler
mov eax,[ebp+8]
mov eax,[eax]
mov [exception], eax
...


Then test in main code:

cmp dword [exception],C0000005
jnz .sice_found



section .data
exception: resd 1

---
At least that will even work when *NOT* single stepping the target in SoftICE.

SiNTAX
September 26th, 2002, 17:17
Well here's my version.. and since I was playing around abit with code obfuscation, I included that aswell

NOTE: feel free to give your comments on the obfuscation, but keep in mind that the test of the result is not hidden away.

SiNTAX
September 26th, 2002, 17:18
LOL! Forgot to attach the file

Solomon
September 29th, 2002, 03:33
In my Win2k, it works no matter whether I press F8 on the INT 1 or not, coz you check the exception code 80000004 in your SEH handler.

Quote:
Originally posted by SiNTAX
LOL! Forgot to attach the file

SiNTAX
September 29th, 2002, 20:52
Indeed So.. what did you think of the code obfuscation?! Did it totally suck, or was it OK?!

evaluator
September 29th, 2002, 22:36
Hello, Solomon!

What exception code produces your w2k system?
(just intresting

SiNTAX
September 30th, 2002, 00:16
The exception code normally is: EXCEPTION_ACCESS_VIOLATION EQU 0C0000005H

If it's not, then there is something else loaded


I tried it on: NT4, NT2k SP1 & WinXP


Solomon... did you mean that the detector does a faulty detect if no debugger is loaded?! Or did you just mean that it worked?!

Solomon
September 30th, 2002, 02:23
Hi,

sorry I didn't express it clearly. The detector works.
It can detect SICE whether I press F8 on the "INT 1" instruction or not.

I have traced through this detector. The exception code is 80000004(STATUS_SINGLE_STEP)

SiNTAX
September 30th, 2002, 08:31
Pfwew

Question... if an INT1 occurs and you handle the exception directly instead of going through Windows (so if the IDT vector of INT1 points to your code), then where is the exception code put on the stack?!

If I read the Intel docs correctly, it should be at [esp], ie stack frame should be:

CS
EIP
Exception Code

But if I have a look at the code of NTALL:

00010875 pusha
00010876 lea ebx, [esp+24h] ;ptr to segment sel.
0001087A lea ecx, [esp+20h] ;ptr to EIP
0001087E mov ecx, ss:[ecx] ;get EIP
00010881 xor eax, eax
00010883 mov ax, ss:[ebx] ;get segment sel.
00010887 push gs
00010889 push ds
0001088A db 66h
0001088A mov gs, ax ;load seg.sel.
0001088D db 66h
0001088D mov ds, cs:word_102AC
00010895 cmp word ptr gs:[ecx-2], 1CDh ;was instr. and INT01?
0001089C jnz short loc_108A3
0001089E lea ecx, [ecx-2]
000108A1 jmp short loc_108AD


Then it seems that the exception code is missing?! (PUSHA adds 20h to stack, so the ESP+20h should give the exception code, but instead gives the EIP)

Anybody care to enlighten me?!

cyberheg
September 30th, 2002, 09:01
Since noone else mentioned anything on it I'd like to say a few things about the obfuscation in your code.

I'm not gonna go into big details (atm. I am writing a obfuscator myself for the last 2 months where I tried also to be innovative and also do alot of research on the subject).

Your obfuscation is weak, very weak. It took me exactly 5 minutes to learn your patterns in generated code and how to deal with them. Since I don't have access to a debugger from work I had to stick with the freeware IDA.

Some hints which you might want to think of is you can devide obfuscation into code flow and runable garbage. It's important to handle things apart to make something strong.

Let me show you a example of what I think is weak:

CODE:0040101A loc_0_40101A: ;
CODE:0040101A ;
CODE:0040101A jnz short loc_0_401013
CODE:0040101C xchg ecx, ecx
CODE:0040101E jz short loc_0_401013

Ida tells me the code goes same places no matter the flag setting.
The push offset; inc [esp] isn't gonna fool anyone for long either.

As for runable garbage it's hardly worth talking about:
mov eax, eax
xchg ecx, ecx

and at the bottom of the file there is alot not dissassemable code. I assume you just padded the file with random bytes or similar. There was very little IDA couldn't handle correctly which is another indication that the code flow obfuscation isn't strong enough.

// CyberHeg

SiNTAX
September 30th, 2002, 09:37
Thanks for the comments.. I must add that I didn't put alot of time into it.. it was one of those 'hey let's try this'-thingies

Anyway I fully agree with you, that correcting the disassembly in IDA isn't much of a problem once you know what is going on.. However, the point is that it takes an effort on the user's part to correct it.

The push/inc [esp] is indeed easy to spot but the point here is to get IDA off track, ie. it doesn't recognize this as a simple JMP, therefor stops the disassembly.

The sequence with all the push's and then the ret's makes understanding the code flow harder (but is easy to single-step trace). So I think this is ok.. ie. it offsets IDA and it confuses the reverser.

As for the runnable garbage.. it's meant to do nothing.. that way you can easily interlace it with existing code.. and it takes a deobfuscator like Imhotep to clean it up.

The crap at the bottom of the file isn't mine It's just something that the NASM/ALINK combo added.

cyberheg
September 30th, 2002, 10:43
Quote:
Originally posted by SiNTAX


The push/inc [esp] is indeed easy to spot but the point here is to get IDA off track, ie. it doesn't recognize this as a simple JMP, therefor stops the disassembly.

The sequence with all the push's and then the ret's makes understanding the code flow harder (but is easy to single-step trace). So I think this is ok.. ie. it offsets IDA and it confuses the reverser.

As for the runnable garbage.. it's meant to do nothing.. that way you can easily interlace it with existing code.. and it takes a deobfuscator like Imhotep to clean it up.

The crap at the bottom of the file isn't mine It's just something that the NASM/ALINK combo added.


With runable garbage I agree with you that it must not interfear with the real code. However it's possible to do many steps to make advanced/intelligent garbage which will stop any disassembler or engine without emulation facility.

For imhotep I found many many holes in it which can make it useless. My last attempt I laffed alot because it managed to clean up some of my code but then again it also made a endless loop out of it which resulted in useless cleanups.

In short what you're trying to do with push $;inc [esp] or those conditional jumps are just 'advanced jumps' but it's possible to make them even more intelligent.

// CyberHeg

SiNTAX
September 30th, 2002, 11:20
Quote:
Originally posted by cyberheg
With runable garbage I agree with you that it must not interfear with the real code. However it's possible to do many steps to make advanced/intelligent garbage which will stop any disassembler or engine without emulation facility.


Very true.. but this was hand-written.. if I'd make an obfuscator tool, it'd make it more challenging ofcourse... throw in alot of register shuffling and crap like that..

And every now and then do some register shuffling that actually changes some registers.. as most reversers tend to get sloppy with repetetive tasks

Quote:

For imhotep I found many many holes in it which can make it useless. My last attempt I laffed alot because it managed to clean up some of my code but then again it also made a endless loop out of it which resulted in useless cleanups.


Imhotep is indeed buggy.. it tends to get stuck alot (hell if you run it on a recent SafeDisc it will clean up too much and then go in an endless loop)

Quote:

In short what you're trying to do with push $;inc [esp] or those conditional jumps are just 'advanced jumps' but it's possible to make them even more intelligent.
// CyberHeg


True.. but intelligence is something for an automated tool.. not for 5 minute handcrafted code. Also, it's hard to hide something in a 20 line program

Hell if I'd have to write an obfuscator, I'd probably grab the LCC compiler source and make it spew out all kinds of crap between valid code sequences.
The things you could do then would make great nightmare material !

SiNTAX
September 30th, 2002, 14:58
Quote:
Originally posted by SiNTAX

If I read the Intel docs correctly, it should be at [esp], ie stack frame should be:

CS
EIP
Exception Code


Guess I should have worn my glasses when reading that document:

Quote:

IA-32 Intel Architecture Software Developer's Manual, Volume 3
p165 / 5-23. Interrupt 1 - Debug Exception (#DB)

Exception Error code

None.

evaluator
October 1st, 2002, 12:00
^DAEMON^!

"Little" question I have to you:

On XP I build Tflag-tracer & successfully tested on your
"DP-teunlock" & "Protect v0.6.7 beta - last.exe".

for "Protect v0.6.7" instuctions counted until OEP = 0C6AD99B h.
(from "KiUserExceptionDispatcher" routine included 4 instruction for each occurence)

Can you somehow confirm this fact!?
(if you have your own tracer or something else)

^DAEMON^
October 4th, 2002, 14:44
hi ev,

just check icedump tracex or revirgin's tracer... i can't check sorry

evaluator
October 5th, 2002, 15:09
heh!

DAEMON, nice joke!
At least you must know, your "protect-last-beta" is NON-traceble by Icedump on my W98se,
and also RV1.5 can't trace it on XP.

OK, so you not have your own tracer..

BTW, what hard targets can you (& all others) recommend for testing my tracer?(for XP)

Already tested:
tElock last
poxylock1.3
pcguard 4.06 demo
XLoK Loader Version 1.3.2714

SiNTAX
October 5th, 2002, 15:13
Quote:
Originally posted by SiNTAX
The exception code normally is: EXCEPTION_ACCESS_VIOLATION EQU 0C0000005H

If it's not, then there is something else loaded



Right.. had an insightful moment and came to the conclusion that fixing this is 'tres simple'

On WinXP: EB 8003f40d 8e

And yippe... detection fixed.

evaluator
October 5th, 2002, 16:38
congratz

Finally you did it!

Can you share some info for me, because you have many OpS.

I interesting for R0 & R3 Segment Register values for each nt-base OS.

For example in XPpro I have:
R3:

CS 001B
DS 0023
SS 0023
ES 0023
FS 0038 or 003B
GS 0000

R0:

CS 0008 <-
DS 0023
SS 0010 <-
ES 0023
FS 0030 <-
GS 0000

So what values are in W2k & NT4 (& 3.5!?)

^DAEMON^
October 5th, 2002, 17:16
hmm strange protections ?

i c u tested already k-kryptor...
aspr ?
peshield ?
pecrypt ?


^DAEMON^

SiNTAX
October 5th, 2002, 22:05
Quote:
Originally posted by evaluator
congratz

Finally you did it!

Can you share some info for me, because you have many OpS.

I interesting for R0 & R3 Segment Register values for each nt-base OS.

So what values are in W2k & NT4 (& 3.5!?)


Well it worked before too... but this is the easiest way ofcourse.. thanks for not helping

I only have WinXP at home... at work I have access to more OS'es but helas no soft ice to check it.

Anyway I think the segment regs are the same for all NT based OS'es.


So.. is your tracer capable of tracing through device driver calls & Ring-0 calls?!

evaluator
October 6th, 2002, 07:23
Crack-tracer's generally are for Ring3 protected proggs

BTW, what R0-tracer you know!? & why is need it for Drivers!?
For such thing need Debuger, IMHO.

nikolatesla20
October 24th, 2002, 19:57
evaluator, could you please answer a question for me?

I was looking at your detector, and trying to understand how it uses the exception frames to its adavantage to detect SI.

Here's the code at the beginning

Code:

:00401000 E80E000000 call 00401013
:00401005 8B5C240C mov ebx, dword ptr [esp+0C]
:00401009 8383B800000004 add dword ptr [ebx+000000B8], 00000004
:00401010 33C0 xor eax, eax
:00401012 C3 ret


:00401013 31C0 xor eax, eax
:00401015 8CC8 mov ax, cs
:00401017 80FC00 cmp ah, 00
:0040101A 755B jne 00401077
:0040101C 6467FF360000 push word ptr fs:[0000] <-no exception handler pushed yet?
:00401022 646789260000 mov fs:[0000], esp
:00401028 CD01 int 01
:0040102A EB12 jmp 0040103E <-- Single step ends up here. U ARE BAD BOY !
:0040102C EB20 jmp 0040104E <-- normal operation here. (GOOD)
:0040102E 6A00 push 00000000 <-- SI present ends up here....how? (YOU ARE BAD BOY!)

* Possible StringData Ref from Data Obj ->"Hello!"
|
:00401030 6800204000 push 00402000

* Possible StringData Ref from Data Obj ->"NTICE FOUND by ^DAEMON^!"
|
:00401035 6840204000 push 00402040
:0040103A 6A00 push 00000000
:0040103C EB2B jmp 00401069



what I'm wondering about is how is the exception handler being set up in the first place - because there is never a push <address> before the fs push itself. So how does the exception frame work?

Also, I understand how the single step could be detected, if INT 1 is "ignored" or in other words, SI "handled" the int1 exception, and the program continues on. (Similar to how SI would react to an int3 "CC" exception, used for bpx). But how, when you are not setting a bpint 1, does it jump over both "JMP" instructions and end up in ^DAEMON^'s code?

I'm reading up on exception frames, etc, but I still dont understand fully how this works. Especially since it doesn't seem like there is ever an address passed in to handle exceptions. Can you please help me ?

-nt20

DakienDX
October 24th, 2002, 21:09
Hello nikolatesla20 !

The expection handler is already pushed on the stack at 0040101Ch.
When the call at 00401000h is executed, it places 00401005h as return address on the stack, which is the same as pushing it directly on the stack.

nikolatesla20
October 24th, 2002, 21:24
Thanks DakienX, I had already thought of that - the only address I could see being pushed was the one in the call instruction.

But I still didnt understand how this would end up landing on the right instruction, the second JMP.


BUT NOW I GET IT ! YAY!

I just remembered that yes this code will get called now after the exception. Right? And it looks like it takes the EIP register and adds 4 to it....to land on the proper "JMP"...

am I on the right track here?

So the way SI responds to the Int 1 must be slightly different - the docs I have say that on an int 1, eip will point to "the next instruction". However I dont think thats right I think it stays on the int1. If in SI it does end up on the next instruction , then I see how this works, because eip+4 would be the "^DAEMON^" detection message.


Code:


:00401000 E80E000000 call 00401013 <--- The call pushes next address on stack.
:00401005 8B5C240C mov ebx, dword ptr [esp+0C] <-- this becomes our exception handler. It adds 4 to EIP.
:00401009 8383B800000004 add dword ptr [ebx+000000B8], 00000004
:00401010 33C0 xor eax, eax
:00401012 C3 ret


:00401013 31C0 xor eax, eax
:00401015 8CC8 mov ax, cs
:00401017 80FC00 cmp ah, 00
:0040101A 755B jne 00401077
:0040101C 6467FF360000 push word ptr fs:[0000]
:00401022 646789260000 mov fs:[0000], esp
:00401028 CD01 int 01
:0040102A EB12 jmp 0040103E <-- If we single step, no exception, no EIP+4
:0040102C EB20 jmp 0040104E <- Normal, for EIP+4 to work, then exception EIP must still be on int 01 instruction.
:0040102E 6A00 push 00000000 <-- EIP+4 lands here if somehow int 01 was handled and EIP pointed to the instruction after it. (SI do this? )

* Possible StringData Ref from Data Obj ->"Hello!"




One thing I don't understand yet tho. On my own machine, which has softice on it, I wrote a little test program using int 01. I set up and exception handler, and everything works as expected. Granted, I am not modifying the EIP register tho.

So is this the *trick*, modifying EIP? Because SI must set EIP to point to a different instruction after the Int 01 than it would be without SI.

-nt20

SiNTAX
October 25th, 2002, 17:57
nikolatesla20, a hint: without SI loaded, you don't get a debug exception but you get another type of exception.

evaluator
October 26th, 2002, 14:57
Hi, nikolatesla20

You wrote too many eNgliSh for me.
IF you Q is:
"Why on clear system Exception-EIP is ON INT01 instruction
& why with NTice Exception-EIP is after INT01"

So answer "jokerly" already done in this thread. But anyway:

On clear system windz in IDT sets 8E byte for INT01 descryptor.
This means DPL=0.

>Virtual-8086 Mode Exceptions
>#GP(0)> (For INT n, INTO, or BOUND instruction)
>If the IOPL is less than 3 or
>>>the DPL of the interrupt-, trap-, or task-gate descriptor is not equal to 3.

So IF Ring3 task attemps to make DPL=0 INT, happens GP = INT0D (not given INT).
In stack processor pushes start of instruction, which made GP.
Windz INT0D hanler-manager will put C0000005 as error code.
So in SEH-report we have error-instruction start + error code (Access Viola.

If NTice (..Sice) loaded, it changes 8E byte to EE, e.g. now INT01 is DPL=3.
Ring3 task normally can attemp DPL=3 INT & in stack will saved next insturction address,
because INT is CALL. Then NTice will check, if set BPX-BPM for task here. If nothing will
found, NTice sends execution to windz INT01 handler as it think out-error happens.
Windz's INT01 handler then manages error & puts 80000004 as error code.

That's all Falks!

BTW
nobody yet explaned??
Maybe I will use SEARCH..

nikolatesla20
October 26th, 2002, 16:33
Thank you evaluator !

I did do a search but I never really got such a clear answer like you gave. Thank you very much

And yes, that is what I was asking, why , without SI, the error would be ON the INT01, and with SI, it would be AFTER the INT01.

I thought it must have had to do with the difference between being a GP (General Protect) or TRAP , but I wasnt sure how windows handled the INT01 by default. I was searching the web also and could not find an answer to this.

-nt20

nikolatesla20
October 28th, 2002, 21:46
In S.I.,

"IDT"

"db <address of IDT base>"

"ALT + D"

Change 14th byte from EE to 8E.

"Enter"

Detection gone. Also, doing this allows you to step into windows exception handler if you are F8'ing.


-nt20

Manko
October 29th, 2002, 07:50
Seems to work with a couple of detectors...

Back to your fine Patch!

Do we not have to rename the ntice.sys and correct for that?

DAEMON has a small detecter that says it finds ntice.sys loaded on w2k... But maybe it's not important yet? Noone uses it...?

/Manko

SiNTAX
October 29th, 2002, 08:49
Quote:
Originally posted by SiNTAX
Right.. had an insightful moment and came to the conclusion that fixing this is 'tres simple'

On WinXP: EB 8003f40d 8e

And yippe... detection fixed.


A bit less verbose

Manko
October 29th, 2002, 08:54
Didn't see that one!
You're in my book of reverance, as well!

/Manko

SiNTAX
October 29th, 2002, 09:26
Quote:
Originally posted by evaluator
Crack-tracer's generally are for Ring3 protected proggs


That's because no-one took the time yet to make one that does R0 too

Quote:


BTW, what R0-tracer you know!? & why is need it for Drivers!?
For such thing need Debuger, IMHO.


Don't know one (unless you count BOCHS). But I see it being useful as some protections use device drivers.. and what is to keep anyone from putting ALOT more code in a device driver (not like the silly SecDrv from SD)

nikolatesla20
October 29th, 2002, 15:32
Oh, sorry SINTAX,

I guess I didnt understand your patch "EB". I didnt mean to steal your idea at all, it just didnt dawn on me !

Sorry 'bout that ! But thank you for all your help !

I was thinking it should be possible to patch ntice.sys for this (or whatever program loads SI - winice.exe?) - for example, ntice.sys is obviously hooking into the IDT. If you look at the IDT function offsets, they lead into softice code. So wherever the SI loader sets up the IDT I would think you could change how it sets the DPL for INT1.

To Manko: There are LOTS of ways to check for SI. Sometimes you just have to go program by program.


-nt20

SiNTAX
October 29th, 2002, 15:44
Quote:
Originally posted by nikolatesla20
Oh, sorry SINTAX,

I guess I didnt understand your patch "EB". I didnt mean to steal your idea at all, it just didnt dawn on me !

Sorry 'bout that ! But thank you for all your help !

-nt20


No problem at all...