UnhookCode thread stopper + example

c++ / delphi package - dll injection and api hooking
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Some interesting new information. I've done this:

(1) SuspendThread(WorkerThread);
(2) GetThreadContext(WorkerThread); -> log
(3) Remove HLT instruction.
(4) ResumeThread(WorkerThread);

When an AV occurred, I've checked the log to see which thread context the worker thread had before I removed the HLT instruction. AVs occurred only if the worker thread was at @Test. With any other EIP the worker thread did not AV. When the worker thread was at @Test, sometimes AVs occurred and sometimes not.

Next test:

(1) .. (3) see above
(4) if context.EIP = @Test then SetThreadContext(WorkerThread, @Test2);
(5) ResumeThread(WorkerThread);

This did *NOT* fix the AVs!!!!!!!

Do you find that as interesting as I find it? It seems to me that although the EIP sais "@Test" that when later the AV occurred, the thread was already in a state which resulted in the AV - even if we used SetThreadContext to point the thread to Test2.

My guess: Probably kernel land was already busy with analyzing the privileged instruction, while GetThreadContext for the worker thread still reported @Test. That's the only explanation I have for this strange test results.

What do you think?
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

that can als be, but the problem is that we cant solve the problem

the only way i think is for looking ACCESS_VIOLATION and PRIVILEGED_INSTRUCTION in KiUserExceptionDispatcher and checking if the EIP is our hooked code...
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

wenn ich jetzt richtig verstanden habe wie du das später vorhast läuft das so ab:

bytes der zu hookenden funktion auslesen (die überschrieben werden sollen) und halt ganz normal in der nextfunktion mit nem jump danach ablegen

danach in allen bytes die mit nem jump überschrieben werden sollen ein HLT setzen (ob von vorne oder hinten beginnend ist egal)

dann solange auf alle threads GetThreadContext aufrufen bis kein thread mehr in den bytes ist die mit HLT überschrieben wurden, gegebenfalls testen ob ein thread davon suspended ist dann kann der hook nicht installiert werden

nachdem kein thread mehr in den HLT funktionen ist (die werden immer auf die nexthook methode umgeleitet bei einer exception) von hinten die bytes der originalen funktion mit dem jmp überschreiben

ist das die idee die dahinter steckt?
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

I'm only overwriting the first byte with HLT. The other bytes can stay as they are. But the rest is exactly as you said.
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

ok should work :P
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

somehting else:

i dont think if its that good to install the exception handler by overwriting the call in KiUserExceptionDispatcher. also this works only in winNT.

so i thought we can install the exception handler by using fs:[0]
if did it here for GetModuleHandle without API:

Code: Select all

procedure GetModuleHandleX;
asm
    PUSH    EBP
    MOV     EBP, ESP
    MOV     ECX, $80000000
    MOV     EBX, EAX
@@goon:
    PUSH    EBX
    PUSH    ECX
    PUSH    EBP
    XOR     EDX, EDX
    PUSH    OFFSET @@MyHandler
    PUSH    DWORD PTR FS:[EDX]
    MOV     FS:[EDX], ESP
    PUSH    [EBP+8]
    PUSH    ECX
    CALL    GetModuleHandleXSub
    JMP     @@BehindMyHandler
@@MyHandler:
    MOV     ESP, [EBP-$4]
    XOR     EAX, EAX
@@BehindMyHandler:
    XOR     EDX, EDX
    POP     DWORD PTR FS:[EDX]
    POP     EDX
    POP     EBP
    POP     ECX
    POP     EBX
    TEST    EAX, EAX
    JNZ     @@Exit
    SUB     ECX, $10000
    TEST    ECX, ECX
    JNZ     @@goon
@@Exit:
    POP     EBP
    RET     $4
end;
installing is:

Code: Select all

    PUSH    OFFSET @@MyHandler
    PUSH    DWORD PTR FS:[0]
    MOV     FS:[0], ESP
its the same like "try" in delphi. but the problem is that u can only use the stack for the offset which u put into FS:[0] so its not possible to install a global exception handler (or u have to find some space in stack which is never overwritten by something else)

so i tried to fake the addressrange that ntdll allows us to use every address for exception handling.
KiUserExceptionDispatcher checks the adress standing in fs:[0] if it is in the stackrange which is stored @ mainthread fs address normally 0x7FFDF000 +4/+8 (+4 = min stack, +8 maxstack) but if i change the values to 0x00000000 and 0xFFFFFFFF KiUserExceptionDistapcher allows me to use the exceptionhandler install address, but the exceptionhandler itself must be outside the range of stack :/
but i try to install the excpetion handler on the highest stack address, and say if its working ;>
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

problem is that we have to add the exception handler for every thread oO i have a look if i can solve the problem easily
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Why don't you like overwriting that call in KiUserExceptionDispatcher? I mean it's very easy and it should not harm. Sure, it doesn't work in win9x, but most of the time I use different techniques for NT and win9x, anyway.

In XP+ we could use the new vectored exception handling. See here:

http://msdn.microsoft.com/msdnmag/issue ... fault.aspx

But that won't help in NT4 and w2k.
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

i think i found a good solution which is working on winNT based systems and 9x

i have to install the exception handler in all threads but that should not be that problem...
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

Code: Select all

function MyHandler(excRec: PExceptionRecord; excCtxt: PContext) : integer; stdcall;
begin
  messagebox(0,pchar(inttohex(integer(excRec.ExceptionAddress),8)),nil,0);
  result := 0;  {problem solved}
end;

procedure InstallHandlerForEveryThread;
var i: integer;
    p: integer;
    max, min, now: integer;
begin
  for i := 0 to $F do
  begin
    p := $7FFD0000+i*$1000;
    if (not isbadreadptr(pointer(p),12)) then
    begin
      min := pinteger(p+8)^;
      max := pinteger(p+4)^;
      now := pinteger(p+0)^;
      if ((now > min) and (now < max)) then
      begin
        pinteger(max-8)^ := now;
        pinteger(max-4)^ := integer(@MyHandler);
        pinteger(p)^ := max-8;
      end;
    end;
  end;
end;
hmpf something is deinstalling my handler :/
maybe i should install it as last handler, ill do same more test
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Well, if you hook a system API in win9x, you may have a lot of threads (in different processes!) in which you have to install exception handlers. I really think that this HLT solution is not very suitable for win9x, at least not for system APIs. The other question is whether there can be any good solution for system APIs in win9x. It's that difficult, because really all threads of all processes are impacted. Anyway, I've not thought about how to solve this problem in win9x, yet.

P.S: Is HLT even protected in win9x? Not sure about that...
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

uall wrote:something is deinstalling my handler :/
maybe i should install it as last handler, ill do same more test
Not sure, but the problem might be that the other threads are not suspended and so they might add new exception handlers all the time, while they're running.
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

adding exception handler all the time should not be that problem if they to it correct (the must add their exception handler on top and point to the exception handler that they have overwritten)

also it doesnt work in the same thread if u do it in 2 different buttons
uall
Posts: 254
Joined: Sun Feb 20, 2005 1:24 pm

Post by uall »

what i did is Structured Exception Handling which is also explained on your link ( http://msdn.microsoft.com/msdnmag/issue ... fault.aspx )

problem is maybe here:

In essence, the SEH frames form a linked list, with the head of the list pointed to by FS:[0]. It's critical to note here that each successive node must be higher on the thread's stack. The operating system enforces this particular rule, meaning that you can't just arbitrarily make your own handler frame and insert it into the list.
madshi
Site Admin
Posts: 10766
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Yeah, the "It's critical to note here that each successive node must be higher on the thread's stack" might be a problem for your idea.

But even without that problem I still don't understand why you don't think it's a problem if another thread installs a new exception handler. I mean if a thread does that it will put its own new handler on the top of the chain. Yours is only 2nd in that case. If the new first handler handles the exception, you'll not see it and thus you can't correct the "privileged" exception. What am I missing?
Post Reply